blob: b910189c4db16952491be6cffbe302fb8b4aebea [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% John Cristy %
17% July 1999 %
18% %
19% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/blob.h"
45#include "magick/blob-private.h"
46#include "magick/cache.h"
47#include "magick/cache-private.h"
48#include "magick/color-private.h"
49#include "magick/composite-private.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
cristy365e58f2010-02-15 02:00:01 +000052#include "magick/geometry.h"
cristy3ed852e2009-09-05 21:47:34 +000053#include "magick/list.h"
54#include "magick/log.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
cristy4789f0d2010-01-10 00:01:06 +000057#include "magick/pixel.h"
cristy3ed852e2009-09-05 21:47:34 +000058#include "magick/pixel-private.h"
cristya21afde2010-07-02 00:45:40 +000059#include "magick/policy.h"
cristy3ed852e2009-09-05 21:47:34 +000060#include "magick/quantum.h"
61#include "magick/random_.h"
62#include "magick/resource_.h"
63#include "magick/semaphore.h"
64#include "magick/splay-tree.h"
65#include "magick/string_.h"
cristya21afde2010-07-02 00:45:40 +000066#include "magick/string-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067#include "magick/thread-private.h"
68#include "magick/utility.h"
69#if defined(MAGICKCORE_ZLIB_DELEGATE)
70#include "zlib.h"
71#endif
72
73/*
cristy30097232010-07-01 02:16:30 +000074 Define declarations.
75*/
76#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
77
78/*
cristy3ed852e2009-09-05 21:47:34 +000079 Typedef declarations.
80*/
81typedef struct _MagickModulo
82{
cristybb503372010-05-27 20:51:26 +000083 ssize_t
cristy3ed852e2009-09-05 21:47:34 +000084 quotient,
85 remainder;
86} MagickModulo;
87
88struct _NexusInfo
89{
90 MagickBooleanType
91 mapped;
92
93 RectangleInfo
94 region;
95
96 MagickSizeType
97 length;
98
99 PixelPacket
100 *cache,
101 *pixels;
102
103 IndexPacket
104 *indexes;
105
cristybb503372010-05-27 20:51:26 +0000106 size_t
cristy3ed852e2009-09-05 21:47:34 +0000107 signature;
108};
109
110/*
111 Forward declarations.
112*/
113#if defined(__cplusplus) || defined(c_plusplus)
114extern "C" {
115#endif
116
117static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
119
120static const PixelPacket
cristybb503372010-05-27 20:51:26 +0000121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000123 *GetVirtualPixelsCache(const Image *);
124
125static MagickBooleanType
cristy09c1c4d2010-06-30 18:23:16 +0000126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
cristybb503372010-05-27 20:51:26 +0000129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
136
137static PixelPacket
cristybb503372010-05-27 20:51:26 +0000138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
cristy3ed852e2009-09-05 21:47:34 +0000142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
cristya4af2e32010-03-08 00:51:56 +0000143 ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000144
145#if defined(__cplusplus) || defined(c_plusplus)
146}
147#endif
148
149/*
150 Global declarations.
151*/
152static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
154
155static SemaphoreInfo
156 *cache_semaphore = (SemaphoreInfo *) NULL;
157
158static SplayTreeInfo
159 *cache_resources = (SplayTreeInfo *) NULL;
cristy3ed852e2009-09-05 21:47:34 +0000160
161/*
162%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
163% %
164% %
165% %
166+ A c q u i r e P i x e l C a c h e %
167% %
168% %
169% %
170%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171%
172% AcquirePixelCache() acquires a pixel cache.
173%
174% The format of the AcquirePixelCache() method is:
175%
cristybb503372010-05-27 20:51:26 +0000176% Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000177%
178% A description of each parameter follows:
179%
180% o number_threads: the number of nexus threads.
181%
182*/
cristybb503372010-05-27 20:51:26 +0000183MagickExport Cache AcquirePixelCache(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000184{
185 CacheInfo
186 *cache_info;
187
188 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
cristy87528ea2009-09-10 14:53:56 +0000193 cache_info->mode=IOMode;
cristy3ed852e2009-09-05 21:47:34 +0000194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
203 GetPixelCacheMethods(&cache_info->methods);
cristy3ed852e2009-09-05 21:47:34 +0000204 cache_info->semaphore=AllocateSemaphoreInfo();
cristy93505cf2010-08-10 21:37:49 +0000205 cache_info->reference_count=1;
cristy3ed852e2009-09-05 21:47:34 +0000206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
211 {
cristy4e1dff62009-10-25 20:36:03 +0000212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000214 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
217 {
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
221 }
cristyf84a1932010-01-03 18:00:18 +0000222 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000223 }
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
226}
227
228/*
229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
230% %
231% %
232% %
233% A c q u i r e P i x e l C a c h e N e x u s %
234% %
235% %
236% %
237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238%
239% AcquirePixelCacheNexus() allocates the NexusInfo structure.
240%
241% The format of the AcquirePixelCacheNexus method is:
242%
cristybb503372010-05-27 20:51:26 +0000243% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000244%
245% A description of each parameter follows:
246%
247% o number_threads: the number of nexus threads.
248%
249*/
cristy2cd7a752010-08-23 00:48:54 +0000250MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +0000251{
cristy3ed852e2009-09-05 21:47:34 +0000252 NexusInfo
253 **nexus_info;
254
cristye076a6e2010-08-15 19:59:43 +0000255 register ssize_t
256 i;
257
cristy3ed852e2009-09-05 21:47:34 +0000258 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
cristybb503372010-05-27 20:51:26 +0000262 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +0000263 {
264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
269 }
270 return(nexus_info);
271}
272
273/*
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275% %
276% %
277% %
cristyd43a46b2010-01-21 02:13:41 +0000278+ A c q u i r e P i x e l C a c h e P i x e l s %
279% %
280% %
281% %
282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283%
284% AcquirePixelCachePixels() returns the pixels associated with the specified
285% image.
286%
287% The format of the AcquirePixelCachePixels() method is:
288%
289% const void *AcquirePixelCachePixels(const Image *image,
290% MagickSizeType *length,ExceptionInfo *exception)
291%
292% A description of each parameter follows:
293%
294% o image: the image.
295%
296% o length: the pixel cache length.
297%
298% o exception: return any errors or warnings in this structure.
299%
300*/
301MagickExport const void *AcquirePixelCachePixels(const Image *image,
302 MagickSizeType *length,ExceptionInfo *exception)
303{
304 CacheInfo
305 *cache_info;
306
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
cristyd43a46b2010-01-21 02:13:41 +0000309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
314 *length=0;
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
319}
320
321/*
322%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323% %
324% %
325% %
cristyf34a1452009-10-24 22:29:27 +0000326+ C a c h e C o m p o n e n t G e n e s i s %
327% %
328% %
329% %
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331%
332% CacheComponentGenesis() instantiates the cache component.
333%
334% The format of the CacheComponentGenesis method is:
335%
336% MagickBooleanType CacheComponentGenesis(void)
337%
338*/
339MagickExport MagickBooleanType CacheComponentGenesis(void)
340{
cristy165b6092009-10-26 13:52:10 +0000341 AcquireSemaphoreInfo(&cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000342 return(MagickTrue);
343}
344
345/*
346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347% %
348% %
349% %
350+ C a c h e C o m p o n e n t T e r m i n u s %
351% %
352% %
353% %
354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355%
356% CacheComponentTerminus() destroys the cache component.
357%
358% The format of the CacheComponentTerminus() method is:
359%
360% CacheComponentTerminus(void)
361%
362*/
363MagickExport void CacheComponentTerminus(void)
364{
cristy18b17442009-10-25 18:36:48 +0000365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
cristyf84a1932010-01-03 18:00:18 +0000367 LockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +0000371 UnlockSemaphoreInfo(cache_semaphore);
cristyf34a1452009-10-24 22:29:27 +0000372 DestroySemaphoreInfo(&cache_semaphore);
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377% %
378% %
379% %
cristy3ed852e2009-09-05 21:47:34 +0000380+ C l i p P i x e l C a c h e N e x u s %
381% %
382% %
383% %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
387% mask. The method returns MagickTrue if the pixel region is clipped,
388% otherwise MagickFalse.
389%
390% The format of the ClipPixelCacheNexus() method is:
391%
392% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393% ExceptionInfo *exception)
394%
395% A description of each parameter follows:
396%
397% o image: the image.
398%
399% o nexus_info: the cache nexus to clip.
400%
401% o exception: return any errors or warnings in this structure.
402%
403*/
404static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
406{
407 CacheInfo
408 *cache_info;
409
410 MagickSizeType
411 number_pixels;
412
413 NexusInfo
414 **clip_nexus,
415 **image_nexus;
416
417 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000418 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +0000419
420 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +0000421 *restrict nexus_indexes,
422 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +0000423
cristy3ed852e2009-09-05 21:47:34 +0000424 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000425 *restrict p,
426 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000427
cristye076a6e2010-08-15 19:59:43 +0000428 register ssize_t
429 i;
430
cristy3ed852e2009-09-05 21:47:34 +0000431 /*
432 Apply clip mask.
433 */
434 if (image->debug != MagickFalse)
435 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
436 if (image->clip_mask == (Image *) NULL)
437 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +0000438 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +0000439 if (cache_info == (Cache) NULL)
440 return(MagickFalse);
441 image_nexus=AcquirePixelCacheNexus(1);
442 clip_nexus=AcquirePixelCacheNexus(1);
443 if ((image_nexus == (NexusInfo **) NULL) ||
444 (clip_nexus == (NexusInfo **) NULL))
445 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
446 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
447 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
448 exception);
449 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
450 q=nexus_info->pixels;
451 nexus_indexes=nexus_info->indexes;
452 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
453 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
454 nexus_info->region.height,clip_nexus[0],exception);
455 number_pixels=(MagickSizeType) nexus_info->region.width*
456 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +0000457 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +0000458 {
459 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
460 break;
461 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
462 {
cristyce70c172010-01-07 17:15:30 +0000463 SetRedPixelComponent(q,GetRedPixelComponent(p));
464 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
465 SetBluePixelComponent(q,GetBluePixelComponent(p));
466 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
cristy3ed852e2009-09-05 21:47:34 +0000467 if (cache_info->active_index_channel != MagickFalse)
468 nexus_indexes[i]=indexes[i];
469 }
470 p++;
471 q++;
472 r++;
473 }
474 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
475 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +0000476 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +0000477 return(MagickFalse);
478 return(MagickTrue);
479}
480
481/*
482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483% %
484% %
485% %
486+ C l o n e P i x e l C a c h e %
487% %
488% %
489% %
490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491%
492% ClonePixelCache() clones a pixel cache.
493%
494% The format of the ClonePixelCache() method is:
495%
496% Cache ClonePixelCache(const Cache cache)
497%
498% A description of each parameter follows:
499%
500% o cache: the pixel cache.
501%
502*/
503MagickExport Cache ClonePixelCache(const Cache cache)
504{
505 CacheInfo
506 *clone_info;
507
508 const CacheInfo
509 *cache_info;
510
511 assert(cache != (const Cache) NULL);
512 cache_info=(const CacheInfo *) cache;
513 assert(cache_info->signature == MagickSignature);
514 if (cache_info->debug != MagickFalse)
515 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
516 cache_info->filename);
517 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
518 if (clone_info == (Cache) NULL)
519 return((Cache) NULL);
520 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
521 return((Cache ) clone_info);
522}
523
524/*
525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
526% %
527% %
528% %
cristy60c44a82009-10-07 00:58:49 +0000529+ C l o n e P i x e l C a c h e P i x e l s %
cristy3ed852e2009-09-05 21:47:34 +0000530% %
531% %
532% %
533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
534% ClonePixelCachePixels() clones the source pixel cache to the destination
535% cache.
536%
537% The format of the ClonePixelCachePixels() method is:
538%
539% MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
540% CacheInfo *source_info,ExceptionInfo *exception)
541%
542% A description of each parameter follows:
543%
544% o cache_info: the pixel cache.
545%
546% o source_info: the source pixel cache.
547%
548% o exception: return any errors or warnings in this structure.
549%
550*/
551
552static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
553{
554 int
555 status;
556
cristy5ee247a2010-02-12 15:42:34 +0000557 status=(-1);
cristyf84a1932010-01-03 18:00:18 +0000558 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy508d9312010-02-10 21:10:30 +0000559 if (cache_info->file != -1)
560 status=close(cache_info->file);
cristy3ed852e2009-09-05 21:47:34 +0000561 cache_info->file=(-1);
562 RelinquishMagickResource(FileResource,1);
cristyf84a1932010-01-03 18:00:18 +0000563 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000564 return(status == -1 ? MagickFalse : MagickTrue);
565}
566
567static void LimitPixelCacheDescriptors(void)
568{
569 register CacheInfo
570 *p,
571 *q;
572
573 /*
574 Limit # of open file descriptors.
575 */
576 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
577 return;
cristyf84a1932010-01-03 18:00:18 +0000578 LockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000579 if (cache_resources == (SplayTreeInfo *) NULL)
580 {
cristyf84a1932010-01-03 18:00:18 +0000581 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000582 return;
583 }
584 ResetSplayTreeIterator(cache_resources);
585 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
586 while (p != (CacheInfo *) NULL)
587 {
588 if ((p->type == DiskCache) && (p->file != -1))
cristy508d9312010-02-10 21:10:30 +0000589 break;
cristy3ed852e2009-09-05 21:47:34 +0000590 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
591 }
592 for (q=p; p != (CacheInfo *) NULL; )
593 {
594 if ((p->type == DiskCache) && (p->file != -1) &&
595 (p->timestamp < q->timestamp))
cristy508d9312010-02-10 21:10:30 +0000596 q=p;
cristy3ed852e2009-09-05 21:47:34 +0000597 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
598 }
599 if (q != (CacheInfo *) NULL)
cristy9e116922010-02-12 20:58:13 +0000600 {
601 /*
602 Close least recently used cache.
603 */
604 (void) close(q->file);
605 q->file=(-1);
606 }
cristyf84a1932010-01-03 18:00:18 +0000607 UnlockSemaphoreInfo(cache_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000608}
609
610static inline MagickSizeType MagickMax(const MagickSizeType x,
611 const MagickSizeType y)
612{
613 if (x > y)
614 return(x);
615 return(y);
616}
617
618static inline MagickSizeType MagickMin(const MagickSizeType x,
619 const MagickSizeType y)
620{
621 if (x < y)
622 return(x);
623 return(y);
624}
625
626static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
627 const MapMode mode)
628{
629 int
630 file;
631
632 /*
633 Open pixel cache on disk.
634 */
cristyf84a1932010-01-03 18:00:18 +0000635 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000636 if (cache_info->file != -1)
637 {
cristyf84a1932010-01-03 18:00:18 +0000638 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000639 return(MagickTrue); /* cache already open */
640 }
641 LimitPixelCacheDescriptors();
642 if (*cache_info->cache_filename == '\0')
643 file=AcquireUniqueFileResource(cache_info->cache_filename);
644 else
645 switch (mode)
646 {
647 case ReadMode:
648 {
649 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
650 break;
651 }
652 case WriteMode:
653 {
654 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
655 O_EXCL,S_MODE);
656 if (file == -1)
657 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
658 break;
659 }
660 case IOMode:
661 default:
662 {
663 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
664 O_EXCL,S_MODE);
665 if (file == -1)
666 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
667 break;
668 }
669 }
670 if (file == -1)
671 {
cristyf84a1932010-01-03 18:00:18 +0000672 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000673 return(MagickFalse);
674 }
675 (void) AcquireMagickResource(FileResource,1);
676 cache_info->file=file;
677 cache_info->timestamp=time(0);
cristyf84a1932010-01-03 18:00:18 +0000678 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000679 return(MagickTrue);
680}
681
682static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
683 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000684 unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000685{
686 register MagickOffsetType
687 i;
688
689 ssize_t
690 count;
691
cristy08a88202010-03-04 19:18:05 +0000692 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000693#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000694 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000695 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
696 {
cristyf84a1932010-01-03 18:00:18 +0000697 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000698 return((MagickOffsetType) -1);
699 }
700#endif
701 count=0;
702 for (i=0; i < (MagickOffsetType) length; i+=count)
703 {
704#if !defined(MAGICKCORE_HAVE_PREAD)
705 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
706 (MagickSizeType) SSIZE_MAX));
707#else
708 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
709 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
710#endif
711 if (count > 0)
712 continue;
713 count=0;
714 if (errno != EINTR)
715 {
716 i=(-1);
717 break;
718 }
719 }
720#if !defined(MAGICKCORE_HAVE_PREAD)
cristyf84a1932010-01-03 18:00:18 +0000721 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000722#endif
723 return(i);
724}
725
726static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
727 const MagickOffsetType offset,const MagickSizeType length,
cristyc47d1f82009-11-26 01:44:43 +0000728 const unsigned char *restrict buffer)
cristy3ed852e2009-09-05 21:47:34 +0000729{
730 register MagickOffsetType
731 i;
732
733 ssize_t
734 count;
735
cristy08a88202010-03-04 19:18:05 +0000736 cache_info->timestamp=time(0);
cristy3ed852e2009-09-05 21:47:34 +0000737#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000738 LockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000739 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
740 {
cristyf84a1932010-01-03 18:00:18 +0000741 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000742 return((MagickOffsetType) -1);
743 }
744#endif
745 count=0;
746 for (i=0; i < (MagickOffsetType) length; i+=count)
747 {
748#if !defined(MAGICKCORE_HAVE_PWRITE)
749 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
750 (MagickSizeType) SSIZE_MAX));
751#else
752 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
753 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
754#endif
755 if (count > 0)
756 continue;
757 count=0;
758 if (errno != EINTR)
759 {
760 i=(-1);
761 break;
762 }
763 }
764#if !defined(MAGICKCORE_HAVE_PWRITE)
cristyf84a1932010-01-03 18:00:18 +0000765 UnlockSemaphoreInfo(cache_info->disk_semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000766#endif
767 return(i);
768}
769
770static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
771 CacheInfo *cache_info,ExceptionInfo *exception)
772{
773 MagickOffsetType
774 count,
775 offset,
776 source_offset;
777
778 MagickSizeType
779 length;
780
cristy3ed852e2009-09-05 21:47:34 +0000781 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000782 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +0000783
cristye076a6e2010-08-15 19:59:43 +0000784 register ssize_t
785 y;
786
cristybb503372010-05-27 20:51:26 +0000787 size_t
cristy3ed852e2009-09-05 21:47:34 +0000788 columns,
789 rows;
790
791 if (cache_info->debug != MagickFalse)
792 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
793 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
794 {
795 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
796 clone_info->cache_filename);
797 return(MagickFalse);
798 }
799 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
800 {
801 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
802 cache_info->cache_filename);
803 return(MagickFalse);
804 }
cristybb503372010-05-27 20:51:26 +0000805 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
806 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000807 if ((clone_info->active_index_channel != MagickFalse) &&
808 (cache_info->active_index_channel != MagickFalse))
809 {
810 register IndexPacket
811 *indexes;
812
813 /*
814 Clone cache indexes.
815 */
816 length=MagickMax(clone_info->columns,cache_info->columns)*
817 sizeof(*indexes);
818 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
819 if (indexes == (IndexPacket *) NULL)
820 {
821 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
822 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
823 return(MagickFalse);
824 }
825 (void) ResetMagickMemory(indexes,0,(size_t) length);
826 length=columns*sizeof(*indexes);
827 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
828 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
829 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
830 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000831 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000832 {
833 source_offset-=cache_info->columns*sizeof(*indexes);
834 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
835 length,(unsigned char *) indexes);
836 if ((MagickSizeType) count != length)
837 break;
838 offset-=clone_info->columns*sizeof(*indexes);
839 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
840 (unsigned char *) indexes);
841 if ((MagickSizeType) count != length)
842 break;
843 }
cristybb503372010-05-27 20:51:26 +0000844 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000845 {
846 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
847 ThrowFileException(exception,CacheError,"UnableToCloneCache",
848 cache_info->cache_filename);
849 return(MagickFalse);
850 }
851 if (clone_info->columns > cache_info->columns)
852 {
853 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
854 (void) ResetMagickMemory(indexes,0,(size_t) length);
855 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
856 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +0000857 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000858 {
859 offset-=clone_info->columns*sizeof(*indexes);
860 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
861 length,(unsigned char *) indexes);
862 if ((MagickSizeType) count != length)
863 break;
864 }
cristybb503372010-05-27 20:51:26 +0000865 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000866 {
867 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
868 ThrowFileException(exception,CacheError,"UnableToCloneCache",
869 cache_info->cache_filename);
870 return(MagickFalse);
871 }
872 }
873 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
874 }
875 /*
876 Clone cache pixels.
877 */
878 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
879 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
880 if (pixels == (PixelPacket *) NULL)
881 {
882 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
883 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
884 return(MagickFalse);
885 }
886 (void) ResetMagickMemory(pixels,0,(size_t) length);
887 length=columns*sizeof(*pixels);
888 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
889 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +0000890 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000891 {
892 source_offset-=cache_info->columns*sizeof(*pixels);
893 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
894 length,(unsigned char *) pixels);
895 if ((MagickSizeType) count != length)
896 break;
897 offset-=clone_info->columns*sizeof(*pixels);
898 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
899 (unsigned char *) pixels);
900 if ((MagickSizeType) count != length)
901 break;
902 }
cristybb503372010-05-27 20:51:26 +0000903 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000904 {
905 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
906 ThrowFileException(exception,CacheError,"UnableToCloneCache",
907 cache_info->cache_filename);
908 return(MagickFalse);
909 }
910 if (clone_info->columns > cache_info->columns)
911 {
912 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
913 sizeof(*pixels);
914 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
915 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +0000916 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000917 {
918 offset-=clone_info->columns*sizeof(*pixels);
919 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
920 (unsigned char *) pixels);
921 if ((MagickSizeType) count != length)
922 break;
923 }
cristybb503372010-05-27 20:51:26 +0000924 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +0000925 {
926 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
927 ThrowFileException(exception,CacheError,"UnableToCloneCache",
928 cache_info->cache_filename);
929 return(MagickFalse);
930 }
931 }
932 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
933 return(MagickTrue);
934}
935
936static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
937 CacheInfo *cache_info,ExceptionInfo *exception)
938{
939 MagickOffsetType
940 count,
941 offset;
942
943 MagickSizeType
944 length;
945
cristy3ed852e2009-09-05 21:47:34 +0000946 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +0000947 *restrict pixels,
948 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +0000949
cristye076a6e2010-08-15 19:59:43 +0000950 register ssize_t
951 y;
952
cristybb503372010-05-27 20:51:26 +0000953 size_t
cristy3ed852e2009-09-05 21:47:34 +0000954 columns,
955 rows;
956
957 if (cache_info->debug != MagickFalse)
958 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
959 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
960 {
961 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
962 cache_info->cache_filename);
963 return(MagickFalse);
964 }
cristybb503372010-05-27 20:51:26 +0000965 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
966 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +0000967 if ((clone_info->active_index_channel != MagickFalse) &&
968 (cache_info->active_index_channel != MagickFalse))
969 {
970 register IndexPacket
971 *indexes,
972 *q;
973
974 /*
975 Clone cache indexes.
976 */
977 length=MagickMax(clone_info->columns,cache_info->columns)*
978 sizeof(*indexes);
979 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
980 if (indexes == (IndexPacket *) NULL)
981 {
982 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
983 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
984 return(MagickFalse);
985 }
986 (void) ResetMagickMemory(indexes,0,(size_t) length);
987 length=columns*sizeof(IndexPacket);
988 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
989 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
990 q=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +0000991 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000992 {
993 offset-=cache_info->columns*sizeof(IndexPacket);
994 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
995 length,(unsigned char *) indexes);
996 if ((MagickSizeType) count != length)
997 break;
998 q-=clone_info->columns;
999 (void) CopyMagickMemory(q,indexes,(size_t) length);
1000 if ((MagickSizeType) count != length)
1001 break;
1002 }
cristybb503372010-05-27 20:51:26 +00001003 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001004 {
1005 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1006 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1007 cache_info->cache_filename);
1008 return(MagickFalse);
1009 }
1010 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1011 }
1012 /*
1013 Clone cache pixels.
1014 */
1015 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1016 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1017 if (pixels == (PixelPacket *) NULL)
1018 {
1019 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1020 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1021 return(MagickFalse);
1022 }
1023 (void) ResetMagickMemory(pixels,0,(size_t) length);
1024 length=columns*sizeof(*pixels);
1025 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1026 q=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001027 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001028 {
1029 offset-=cache_info->columns*sizeof(*pixels);
1030 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1031 (unsigned char *) pixels);
1032 if ((MagickSizeType) count != length)
1033 break;
1034 q-=clone_info->columns;
1035 (void) CopyMagickMemory(q,pixels,(size_t) length);
1036 }
cristybb503372010-05-27 20:51:26 +00001037 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001038 {
1039 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1040 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1041 cache_info->cache_filename);
1042 return(MagickFalse);
1043 }
1044 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1045 return(MagickTrue);
1046}
1047
1048static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1049 CacheInfo *cache_info,ExceptionInfo *exception)
1050{
1051 MagickOffsetType
1052 count,
1053 offset;
1054
1055 MagickSizeType
1056 length;
1057
cristy3ed852e2009-09-05 21:47:34 +00001058 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001059 *restrict p,
1060 *restrict pixels;
cristy3ed852e2009-09-05 21:47:34 +00001061
cristye076a6e2010-08-15 19:59:43 +00001062 register ssize_t
1063 y;
1064
cristybb503372010-05-27 20:51:26 +00001065 size_t
cristy3ed852e2009-09-05 21:47:34 +00001066 columns,
1067 rows;
1068
1069 if (cache_info->debug != MagickFalse)
1070 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1071 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1072 {
1073 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1074 clone_info->cache_filename);
1075 return(MagickFalse);
1076 }
cristybb503372010-05-27 20:51:26 +00001077 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1078 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001079 if ((clone_info->active_index_channel != MagickFalse) &&
1080 (cache_info->active_index_channel != MagickFalse))
1081 {
1082 register IndexPacket
1083 *p,
1084 *indexes;
1085
1086 /*
1087 Clone cache indexes.
1088 */
1089 length=MagickMax(clone_info->columns,cache_info->columns)*
1090 sizeof(*indexes);
1091 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1092 if (indexes == (IndexPacket *) NULL)
1093 {
1094 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1095 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1096 return(MagickFalse);
1097 }
1098 (void) ResetMagickMemory(indexes,0,(size_t) length);
1099 length=columns*sizeof(*indexes);
1100 p=cache_info->indexes+cache_info->columns*rows;
1101 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1102 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001103 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001104 {
1105 p-=cache_info->columns;
1106 (void) CopyMagickMemory(indexes,p,(size_t) length);
1107 offset-=clone_info->columns*sizeof(*indexes);
1108 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1109 (unsigned char *) indexes);
1110 if ((MagickSizeType) count != length)
1111 break;
1112 }
cristybb503372010-05-27 20:51:26 +00001113 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001114 {
1115 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1116 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1117 cache_info->cache_filename);
1118 return(MagickFalse);
1119 }
1120 if (clone_info->columns > cache_info->columns)
1121 {
1122 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1123 (void) ResetMagickMemory(indexes,0,(size_t) length);
1124 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1125 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
cristybb503372010-05-27 20:51:26 +00001126 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001127 {
1128 offset-=clone_info->columns*sizeof(*indexes);
1129 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1130 length,(unsigned char *) indexes);
1131 if ((MagickSizeType) count != length)
1132 break;
1133 }
cristybb503372010-05-27 20:51:26 +00001134 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001135 {
1136 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1137 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1138 cache_info->cache_filename);
1139 return(MagickFalse);
1140 }
1141 }
1142 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1143 }
1144 /*
1145 Clone cache pixels.
1146 */
1147 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1148 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1149 if (pixels == (PixelPacket *) NULL)
1150 {
1151 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1152 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1153 return(MagickFalse);
1154 }
1155 (void) ResetMagickMemory(pixels,0,(size_t) length);
1156 length=columns*sizeof(*pixels);
1157 p=cache_info->pixels+cache_info->columns*rows;
1158 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
cristybb503372010-05-27 20:51:26 +00001159 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001160 {
1161 p-=cache_info->columns;
1162 (void) CopyMagickMemory(pixels,p,(size_t) length);
1163 offset-=clone_info->columns*sizeof(*pixels);
1164 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1165 (unsigned char *) pixels);
1166 if ((MagickSizeType) count != length)
1167 break;
1168 }
cristybb503372010-05-27 20:51:26 +00001169 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001170 {
1171 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1172 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1173 cache_info->cache_filename);
1174 return(MagickFalse);
1175 }
1176 if (clone_info->columns > cache_info->columns)
1177 {
1178 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1179 sizeof(*pixels);
1180 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1181 (void) ResetMagickMemory(pixels,0,(size_t) length);
cristybb503372010-05-27 20:51:26 +00001182 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001183 {
1184 offset-=clone_info->columns*sizeof(*pixels);
1185 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1186 (unsigned char *) pixels);
1187 if ((MagickSizeType) count != length)
1188 break;
1189 }
cristybb503372010-05-27 20:51:26 +00001190 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00001191 {
1192 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1193 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1194 cache_info->cache_filename);
1195 return(MagickFalse);
1196 }
1197 }
1198 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1199 return(MagickTrue);
1200}
1201
1202static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1203 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1204{
cristy3ed852e2009-09-05 21:47:34 +00001205 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00001206 *restrict pixels,
1207 *restrict source_pixels;
cristy3ed852e2009-09-05 21:47:34 +00001208
cristye076a6e2010-08-15 19:59:43 +00001209 register ssize_t
1210 y;
cristy3ed852e2009-09-05 21:47:34 +00001211
cristybb503372010-05-27 20:51:26 +00001212 size_t
cristy3ed852e2009-09-05 21:47:34 +00001213 columns,
cristye076a6e2010-08-15 19:59:43 +00001214 length,
cristy3ed852e2009-09-05 21:47:34 +00001215 rows;
1216
1217 if (cache_info->debug != MagickFalse)
1218 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
cristybb503372010-05-27 20:51:26 +00001219 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1220 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
cristy3ed852e2009-09-05 21:47:34 +00001221 if ((clone_info->active_index_channel != MagickFalse) &&
1222 (cache_info->active_index_channel != MagickFalse))
1223 {
1224 register IndexPacket
1225 *indexes,
1226 *source_indexes;
1227
1228 /*
1229 Clone cache indexes.
1230 */
1231 length=columns*sizeof(*indexes);
1232 if (clone_info->columns == cache_info->columns)
1233 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1234 length*rows);
1235 else
1236 {
1237 source_indexes=cache_info->indexes+cache_info->columns*rows;
1238 indexes=clone_info->indexes+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001239 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001240 {
1241 source_indexes-=cache_info->columns;
1242 indexes-=clone_info->columns;
1243 (void) CopyMagickMemory(indexes,source_indexes,length);
1244 }
1245 if (clone_info->columns > cache_info->columns)
1246 {
1247 length=(clone_info->columns-cache_info->columns)*
1248 sizeof(*indexes);
1249 indexes=clone_info->indexes+clone_info->columns*rows+
1250 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001251 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001252 {
1253 indexes-=clone_info->columns;
1254 (void) ResetMagickMemory(indexes,0,length);
1255 }
1256 }
1257 }
1258 }
1259 /*
1260 Clone cache pixels.
1261 */
1262 length=columns*sizeof(*pixels);
1263 if (clone_info->columns == cache_info->columns)
1264 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1265 else
1266 {
1267 source_pixels=cache_info->pixels+cache_info->columns*rows;
1268 pixels=clone_info->pixels+clone_info->columns*rows;
cristybb503372010-05-27 20:51:26 +00001269 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001270 {
1271 source_pixels-=cache_info->columns;
1272 pixels-=clone_info->columns;
1273 (void) CopyMagickMemory(pixels,source_pixels,length);
1274 }
1275 if (clone_info->columns > cache_info->columns)
1276 {
1277 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1278 pixels=clone_info->pixels+clone_info->columns*rows+
1279 cache_info->columns;
cristybb503372010-05-27 20:51:26 +00001280 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001281 {
1282 pixels-=clone_info->columns;
1283 (void) ResetMagickMemory(pixels,0,length);
1284 }
1285 }
1286 }
1287 return(MagickTrue);
1288}
1289
1290static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1291 CacheInfo *cache_info,ExceptionInfo *exception)
1292{
1293 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1294 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1295 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1296 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1297 if (cache_info->type == DiskCache)
1298 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1299 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1300}
1301
1302/*
1303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304% %
1305% %
1306% %
1307+ C l o n e P i x e l C a c h e M e t h o d s %
1308% %
1309% %
1310% %
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312%
1313% ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1314% another.
1315%
1316% The format of the ClonePixelCacheMethods() method is:
1317%
1318% void ClonePixelCacheMethods(Cache clone,const Cache cache)
1319%
1320% A description of each parameter follows:
1321%
1322% o clone: Specifies a pointer to a Cache structure.
1323%
1324% o cache: the pixel cache.
1325%
1326*/
1327MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1328{
1329 CacheInfo
1330 *cache_info,
1331 *source_info;
1332
1333 assert(clone != (Cache) NULL);
1334 source_info=(CacheInfo *) clone;
1335 assert(source_info->signature == MagickSignature);
1336 if (source_info->debug != MagickFalse)
1337 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1338 source_info->filename);
1339 assert(cache != (Cache) NULL);
1340 cache_info=(CacheInfo *) cache;
1341 assert(cache_info->signature == MagickSignature);
1342 source_info->methods=cache_info->methods;
1343}
1344
1345/*
1346%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347% %
1348% %
1349% %
1350+ D e s t r o y I m a g e P i x e l C a c h e %
1351% %
1352% %
1353% %
1354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1355%
1356% DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1357%
1358% The format of the DestroyImagePixelCache() method is:
1359%
1360% void DestroyImagePixelCache(Image *image)
1361%
1362% A description of each parameter follows:
1363%
1364% o image: the image.
1365%
1366*/
1367static void DestroyImagePixelCache(Image *image)
1368{
1369 assert(image != (Image *) NULL);
1370 assert(image->signature == MagickSignature);
1371 if (image->debug != MagickFalse)
1372 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1373 if (image->cache == (void *) NULL)
1374 return;
1375 image->cache=DestroyPixelCache(image->cache);
1376}
1377
1378/*
1379%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1380% %
1381% %
1382% %
1383+ D e s t r o y I m a g e P i x e l s %
1384% %
1385% %
1386% %
1387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1388%
1389% DestroyImagePixels() deallocates memory associated with the pixel cache.
1390%
1391% The format of the DestroyImagePixels() method is:
1392%
1393% void DestroyImagePixels(Image *image)
1394%
1395% A description of each parameter follows:
1396%
1397% o image: the image.
1398%
1399*/
1400MagickExport void DestroyImagePixels(Image *image)
1401{
1402 CacheInfo
1403 *cache_info;
1404
1405 assert(image != (const Image *) NULL);
1406 assert(image->signature == MagickSignature);
1407 if (image->debug != MagickFalse)
1408 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1409 assert(image->cache != (Cache) NULL);
1410 cache_info=(CacheInfo *) image->cache;
1411 assert(cache_info->signature == MagickSignature);
1412 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1413 return;
1414 cache_info->methods.destroy_pixel_handler(image);
1415}
1416
1417/*
1418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419% %
1420% %
1421% %
1422+ D e s t r o y P i x e l C a c h e %
1423% %
1424% %
1425% %
1426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1427%
1428% DestroyPixelCache() deallocates memory associated with the pixel cache.
1429%
1430% The format of the DestroyPixelCache() method is:
1431%
1432% Cache DestroyPixelCache(Cache cache)
1433%
1434% A description of each parameter follows:
1435%
1436% o cache: the pixel cache.
1437%
1438*/
1439
1440static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1441{
1442 switch (cache_info->type)
1443 {
1444 case MemoryCache:
1445 {
1446 if (cache_info->mapped == MagickFalse)
1447 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1448 cache_info->pixels);
1449 else
1450 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1451 (size_t) cache_info->length);
1452 RelinquishMagickResource(MemoryResource,cache_info->length);
1453 break;
1454 }
1455 case MapCache:
1456 {
1457 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1458 cache_info->length);
1459 RelinquishMagickResource(MapResource,cache_info->length);
1460 }
1461 case DiskCache:
1462 {
1463 if (cache_info->file != -1)
1464 (void) ClosePixelCacheOnDisk(cache_info);
1465 RelinquishMagickResource(DiskResource,cache_info->length);
1466 break;
1467 }
1468 default:
1469 break;
1470 }
1471 cache_info->type=UndefinedCache;
1472 cache_info->mapped=MagickFalse;
1473 cache_info->indexes=(IndexPacket *) NULL;
1474}
1475
1476MagickExport Cache DestroyPixelCache(Cache cache)
1477{
1478 CacheInfo
1479 *cache_info;
1480
cristy3ed852e2009-09-05 21:47:34 +00001481 assert(cache != (Cache) NULL);
1482 cache_info=(CacheInfo *) cache;
1483 assert(cache_info->signature == MagickSignature);
1484 if (cache_info->debug != MagickFalse)
1485 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1486 cache_info->filename);
cristyf84a1932010-01-03 18:00:18 +00001487 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001488 cache_info->reference_count--;
1489 if (cache_info->reference_count != 0)
1490 {
cristyf84a1932010-01-03 18:00:18 +00001491 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001492 return((Cache) NULL);
1493 }
cristyf84a1932010-01-03 18:00:18 +00001494 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001495 if (cache_resources != (SplayTreeInfo *) NULL)
1496 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
cristy5b8de732009-09-10 23:50:40 +00001497 if (cache_info->debug != MagickFalse)
1498 {
1499 char
1500 message[MaxTextExtent];
1501
1502 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1503 cache_info->filename);
1504 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1505 }
cristyc2e1bdd2009-09-10 23:43:34 +00001506 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1507 (cache_info->type != DiskCache)))
1508 RelinquishPixelCachePixels(cache_info);
1509 else
1510 {
1511 RelinquishPixelCachePixels(cache_info);
1512 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1513 }
cristy3ed852e2009-09-05 21:47:34 +00001514 *cache_info->cache_filename='\0';
1515 if (cache_info->nexus_info != (NexusInfo **) NULL)
1516 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1517 cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001518 if (cache_info->random_info != (RandomInfo *) NULL)
1519 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
cristy3ed852e2009-09-05 21:47:34 +00001520 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1521 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1522 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1523 DestroySemaphoreInfo(&cache_info->semaphore);
cristy154a1e22010-02-15 00:28:37 +00001524 cache_info->signature=(~MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001525 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1526 cache=(Cache) NULL;
1527 return(cache);
1528}
1529
1530/*
1531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532% %
1533% %
1534% %
1535+ D e s t r o y P i x e l C a c h e N e x u s %
1536% %
1537% %
1538% %
1539%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540%
1541% DestroyPixelCacheNexus() destroys a pixel cache nexus.
1542%
1543% The format of the DestroyPixelCacheNexus() method is:
1544%
1545% NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
cristybb503372010-05-27 20:51:26 +00001546% const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001547%
1548% A description of each parameter follows:
1549%
1550% o nexus_info: the nexus to destroy.
1551%
1552% o number_threads: the number of nexus threads.
1553%
1554*/
1555
1556static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1557{
1558 if (nexus_info->mapped == MagickFalse)
1559 (void) RelinquishMagickMemory(nexus_info->cache);
1560 else
1561 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1562 nexus_info->cache=(PixelPacket *) NULL;
1563 nexus_info->pixels=(PixelPacket *) NULL;
1564 nexus_info->indexes=(IndexPacket *) NULL;
1565 nexus_info->length=0;
1566 nexus_info->mapped=MagickFalse;
1567}
1568
1569MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
cristybb503372010-05-27 20:51:26 +00001570 const size_t number_threads)
cristy3ed852e2009-09-05 21:47:34 +00001571{
cristybb503372010-05-27 20:51:26 +00001572 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001573 i;
1574
1575 assert(nexus_info != (NexusInfo **) NULL);
cristybb503372010-05-27 20:51:26 +00001576 for (i=0; i < (ssize_t) number_threads; i++)
cristy3ed852e2009-09-05 21:47:34 +00001577 {
1578 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1579 RelinquishCacheNexusPixels(nexus_info[i]);
1580 nexus_info[i]->signature=(~MagickSignature);
1581 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1582 }
1583 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1584 return(nexus_info);
1585}
1586
1587/*
1588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589% %
1590% %
1591% %
cristy3ed852e2009-09-05 21:47:34 +00001592+ G e t A u t h e n t i c I n d e x e s F r o m C a c h e %
1593% %
1594% %
1595% %
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597%
1598% GetAuthenticIndexesFromCache() returns the indexes associated with the last
1599% call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1600%
1601% The format of the GetAuthenticIndexesFromCache() method is:
1602%
1603% IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1604%
1605% A description of each parameter follows:
1606%
1607% o image: the image.
1608%
1609*/
1610static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1611{
1612 CacheInfo
1613 *cache_info;
1614
1615 IndexPacket
1616 *indexes;
1617
cristy6ebe97c2010-07-03 01:17:28 +00001618 int
cristy3ed852e2009-09-05 21:47:34 +00001619 id;
1620
cristy3ed852e2009-09-05 21:47:34 +00001621 cache_info=(CacheInfo *) image->cache;
1622 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001623 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001624 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1625 return(indexes);
1626}
1627
1628/*
1629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630% %
1631% %
1632% %
1633% G e t A u t h e n t i c I n d e x Q u e u e %
1634% %
1635% %
1636% %
1637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638%
1639% GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1640% indexes associated with the last call to QueueAuthenticPixels() or
1641% GetVirtualPixels(). NULL is returned if the black channel or colormap
1642% indexes are not available.
1643%
1644% The format of the GetAuthenticIndexQueue() method is:
1645%
1646% IndexPacket *GetAuthenticIndexQueue(const Image *image)
1647%
1648% A description of each parameter follows:
1649%
1650% o image: the image.
1651%
1652*/
1653MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1654{
1655 CacheInfo
1656 *cache_info;
1657
1658 assert(image != (const Image *) NULL);
1659 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001660 assert(image->cache != (Cache) NULL);
1661 cache_info=(CacheInfo *) image->cache;
1662 assert(cache_info->signature == MagickSignature);
1663 if (cache_info->methods.get_authentic_indexes_from_handler ==
1664 (GetAuthenticIndexesFromHandler) NULL)
1665 return((IndexPacket *) NULL);
1666 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1667}
1668
1669/*
1670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1671% %
1672% %
1673% %
1674+ G e t A u t h e n t i c P i x e l C a c h e N e x u s %
1675% %
1676% %
1677% %
1678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1679%
1680% GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1681% disk pixel cache as defined by the geometry parameters. A pointer to the
1682% pixels is returned if the pixels are transferred, otherwise a NULL is
1683% returned.
1684%
1685% The format of the GetAuthenticPixelCacheNexus() method is:
1686%
cristybb503372010-05-27 20:51:26 +00001687% PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1688% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001689% NexusInfo *nexus_info,ExceptionInfo *exception)
1690%
1691% A description of each parameter follows:
1692%
1693% o image: the image.
1694%
1695% o x,y,columns,rows: These values define the perimeter of a region of
1696% pixels.
1697%
1698% o nexus_info: the cache nexus to return.
1699%
1700% o exception: return any errors or warnings in this structure.
1701%
1702*/
1703
1704static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1705 NexusInfo *nexus_info)
1706{
1707 MagickOffsetType
1708 offset;
1709
cristy73724512010-04-12 14:43:14 +00001710 if (cache_info->type == PingCache)
1711 return(MagickTrue);
cristy3ed852e2009-09-05 21:47:34 +00001712 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1713 nexus_info->region.x;
1714 if (nexus_info->pixels != (cache_info->pixels+offset))
1715 return(MagickFalse);
1716 return(MagickTrue);
1717}
1718
cristye076a6e2010-08-15 19:59:43 +00001719MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1720 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001721 NexusInfo *nexus_info,ExceptionInfo *exception)
1722{
1723 CacheInfo
1724 *cache_info;
1725
1726 PixelPacket
1727 *pixels;
1728
1729 /*
1730 Transfer pixels from the cache.
1731 */
1732 assert(image != (Image *) NULL);
1733 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001734 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1735 if (pixels == (PixelPacket *) NULL)
1736 return((PixelPacket *) NULL);
1737 cache_info=(CacheInfo *) image->cache;
1738 assert(cache_info->signature == MagickSignature);
1739 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1740 return(pixels);
1741 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1742 return((PixelPacket *) NULL);
1743 if (cache_info->active_index_channel != MagickFalse)
1744 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1745 return((PixelPacket *) NULL);
1746 return(pixels);
1747}
1748
1749/*
1750%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1751% %
1752% %
1753% %
1754+ G e t A u t h e n t i c P i x e l s F r o m C a c h e %
1755% %
1756% %
1757% %
1758%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759%
1760% GetAuthenticPixelsFromCache() returns the pixels associated with the last
1761% call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1762%
1763% The format of the GetAuthenticPixelsFromCache() method is:
1764%
1765% PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1766%
1767% A description of each parameter follows:
1768%
1769% o image: the image.
1770%
1771*/
1772static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1773{
1774 CacheInfo
1775 *cache_info;
1776
cristy6ebe97c2010-07-03 01:17:28 +00001777 int
cristy3ed852e2009-09-05 21:47:34 +00001778 id;
1779
1780 PixelPacket
1781 *pixels;
1782
cristy3ed852e2009-09-05 21:47:34 +00001783 cache_info=(CacheInfo *) image->cache;
1784 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001785 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001786 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1787 return(pixels);
1788}
1789
1790/*
1791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1792% %
1793% %
1794% %
1795% G e t A u t h e n t i c P i x e l Q u e u e %
1796% %
1797% %
1798% %
1799%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1800%
1801% GetAuthenticPixelQueue() returns the authentic pixels associated with the
1802% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1803%
1804% The format of the GetAuthenticPixelQueue() method is:
1805%
1806% PixelPacket *GetAuthenticPixelQueue(const Image image)
1807%
1808% A description of each parameter follows:
1809%
1810% o image: the image.
1811%
1812*/
1813MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1814{
1815 CacheInfo
1816 *cache_info;
1817
1818 assert(image != (const Image *) NULL);
1819 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001820 assert(image->cache != (Cache) NULL);
1821 cache_info=(CacheInfo *) image->cache;
1822 assert(cache_info->signature == MagickSignature);
1823 if (cache_info->methods.get_authentic_pixels_from_handler ==
1824 (GetAuthenticPixelsFromHandler) NULL)
1825 return((PixelPacket *) NULL);
1826 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1827}
1828
1829/*
1830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1831% %
1832% %
1833% %
1834% G e t A u t h e n t i c P i x e l s %
1835% %
1836% %
1837% %
1838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1839%
1840% GetAuthenticPixels() obtains a pixel region for read/write access. If the
1841% region is successfully accessed, a pointer to a PixelPacket array
1842% representing the region is returned, otherwise NULL is returned.
1843%
1844% The returned pointer may point to a temporary working copy of the pixels
1845% or it may point to the original pixels in memory. Performance is maximized
1846% if the selected region is part of one row, or one or more full rows, since
1847% then there is opportunity to access the pixels in-place (without a copy)
cristyad4e5b22010-01-10 00:04:19 +00001848% if the image is in memory, or in a memory-mapped file. The returned pointer
1849% must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00001850%
1851% Pixels accessed via the returned pointer represent a simple array of type
1852% PixelPacket. If the image type is CMYK or if the storage class is
1853% PseduoClass, call GetAuthenticIndexQueue() after invoking
1854% GetAuthenticPixels() to obtain the black color component or colormap indexes
1855% (of type IndexPacket) corresponding to the region. Once the PixelPacket
1856% (and/or IndexPacket) array has been updated, the changes must be saved back
1857% to the underlying image using SyncAuthenticPixels() or they may be lost.
1858%
1859% The format of the GetAuthenticPixels() method is:
1860%
cristy5f959472010-05-27 22:19:46 +00001861% PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1862% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001863% ExceptionInfo *exception)
1864%
1865% A description of each parameter follows:
1866%
1867% o image: the image.
1868%
1869% o x,y,columns,rows: These values define the perimeter of a region of
1870% pixels.
1871%
1872% o exception: return any errors or warnings in this structure.
1873%
1874*/
cristybb503372010-05-27 20:51:26 +00001875MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1876 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001877 ExceptionInfo *exception)
1878{
1879 CacheInfo
1880 *cache_info;
1881
1882 PixelPacket
1883 *pixels;
1884
1885 assert(image != (Image *) NULL);
1886 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00001887 assert(image->cache != (Cache) NULL);
1888 cache_info=(CacheInfo *) image->cache;
1889 assert(cache_info->signature == MagickSignature);
1890 if (cache_info->methods.get_authentic_pixels_handler ==
1891 (GetAuthenticPixelsHandler) NULL)
1892 return((PixelPacket *) NULL);
1893 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1894 rows,exception);
1895 return(pixels);
1896}
1897
1898/*
1899%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1900% %
1901% %
1902% %
1903+ G e t A u t h e n t i c P i x e l s C a c h e %
1904% %
1905% %
1906% %
1907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1908%
1909% GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1910% as defined by the geometry parameters. A pointer to the pixels is returned
1911% if the pixels are transferred, otherwise a NULL is returned.
1912%
1913% The format of the GetAuthenticPixelsCache() method is:
1914%
cristybb503372010-05-27 20:51:26 +00001915% PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1916% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001917% ExceptionInfo *exception)
1918%
1919% A description of each parameter follows:
1920%
1921% o image: the image.
1922%
1923% o x,y,columns,rows: These values define the perimeter of a region of
1924% pixels.
1925%
1926% o exception: return any errors or warnings in this structure.
1927%
1928*/
cristybb503372010-05-27 20:51:26 +00001929static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1930 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00001931 ExceptionInfo *exception)
1932{
1933 CacheInfo
1934 *cache_info;
1935
cristy6ebe97c2010-07-03 01:17:28 +00001936 int
cristy3ed852e2009-09-05 21:47:34 +00001937 id;
1938
1939 PixelPacket
1940 *pixels;
1941
cristy77ff0282010-09-13 00:51:10 +00001942 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00001943 if (cache_info == (Cache) NULL)
1944 return((PixelPacket *) NULL);
1945 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001946 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001947 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1948 cache_info->nexus_info[id],exception);
1949 return(pixels);
1950}
1951
1952/*
1953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1954% %
1955% %
1956% %
1957+ G e t I m a g e E x t e n t %
1958% %
1959% %
1960% %
1961%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1962%
1963% GetImageExtent() returns the extent of the pixels associated with the
1964% last call to QueueAuthenticPixels() or GetAuthenticPixels().
1965%
1966% The format of the GetImageExtent() method is:
1967%
1968% MagickSizeType GetImageExtent(const Image *image)
1969%
1970% A description of each parameter follows:
1971%
1972% o image: the image.
1973%
1974*/
1975MagickExport MagickSizeType GetImageExtent(const Image *image)
1976{
1977 CacheInfo
1978 *cache_info;
1979
cristy6ebe97c2010-07-03 01:17:28 +00001980 int
cristy3ed852e2009-09-05 21:47:34 +00001981 id;
1982
1983 MagickSizeType
1984 extent;
1985
1986 assert(image != (Image *) NULL);
1987 assert(image->signature == MagickSignature);
1988 if (image->debug != MagickFalse)
1989 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1990 assert(image->cache != (Cache) NULL);
1991 cache_info=(CacheInfo *) image->cache;
1992 assert(cache_info->signature == MagickSignature);
1993 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00001994 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00001995 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
1996 return(extent);
1997}
1998
1999/*
2000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2001% %
2002% %
2003% %
2004+ G e t I m a g e P i x e l C a c h e %
2005% %
2006% %
2007% %
2008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2009%
2010% GetImagePixelCache() ensures that there is only a single reference to the
2011% pixel cache to be modified, updating the provided cache pointer to point to
2012% a clone of the original pixel cache if necessary.
2013%
2014% The format of the GetImagePixelCache method is:
2015%
2016% Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2017% ExceptionInfo *exception)
2018%
2019% A description of each parameter follows:
2020%
2021% o image: the image.
2022%
2023% o clone: any value other than MagickFalse clones the cache pixels.
2024%
2025% o exception: return any errors or warnings in this structure.
2026%
2027*/
cristy3ed852e2009-09-05 21:47:34 +00002028static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2029{
2030 CacheInfo
2031 *cache_info;
2032
2033 /*
2034 Does the image match the pixel cache morphology?
2035 */
2036 cache_info=(CacheInfo *) image->cache;
2037 if ((image->storage_class != cache_info->storage_class) ||
2038 (image->colorspace != cache_info->colorspace) ||
2039 (image->columns != cache_info->columns) ||
2040 (image->rows != cache_info->rows) ||
2041 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2042 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2043 return(MagickFalse);
2044 return(MagickTrue);
2045}
2046
cristy77ff0282010-09-13 00:51:10 +00002047static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2048 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002049{
2050 CacheInfo
2051 *cache_info;
2052
cristy3ed852e2009-09-05 21:47:34 +00002053 MagickBooleanType
cristy4320e0e2009-09-10 15:00:08 +00002054 destroy,
cristy3ed852e2009-09-05 21:47:34 +00002055 status;
2056
cristy50a10922010-02-15 18:35:25 +00002057 static MagickSizeType
cristy6ebe97c2010-07-03 01:17:28 +00002058 cpu_throttle = 0,
2059 cycles = 0,
cristy50a10922010-02-15 18:35:25 +00002060 time_limit = 0;
2061
cristy1ea34962010-07-01 19:49:21 +00002062 static time_t
cristya21afde2010-07-02 00:45:40 +00002063 cache_genesis = 0;
cristy1ea34962010-07-01 19:49:21 +00002064
cristyc4f9f132010-03-04 18:50:01 +00002065 status=MagickTrue;
2066 LockSemaphoreInfo(image->semaphore);
cristy6ebe97c2010-07-03 01:17:28 +00002067 if (cpu_throttle == 0)
2068 {
2069 char
2070 *limit;
2071
2072 /*
2073 Set CPU throttle in milleseconds.
2074 */
2075 cpu_throttle=MagickResourceInfinity;
2076 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2077 if (limit == (char *) NULL)
2078 limit=GetPolicyValue("throttle");
2079 if (limit != (char *) NULL)
2080 {
2081 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2082 limit=DestroyString(limit);
2083 }
2084 }
2085 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2086 MagickDelay(cpu_throttle);
cristy1ea34962010-07-01 19:49:21 +00002087 if (time_limit == 0)
2088 {
cristy6ebe97c2010-07-03 01:17:28 +00002089 /*
2090 Set the exire time in seconds.
2091 */
cristy1ea34962010-07-01 19:49:21 +00002092 time_limit=GetMagickResourceLimit(TimeResource);
cristya21afde2010-07-02 00:45:40 +00002093 cache_genesis=time((time_t *) NULL);
cristy1ea34962010-07-01 19:49:21 +00002094 }
2095 if ((time_limit != MagickResourceInfinity) &&
cristya21afde2010-07-02 00:45:40 +00002096 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
cristy1ea34962010-07-01 19:49:21 +00002097 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
cristy3ed852e2009-09-05 21:47:34 +00002098 assert(image->cache != (Cache) NULL);
2099 cache_info=(CacheInfo *) image->cache;
cristy4320e0e2009-09-10 15:00:08 +00002100 destroy=MagickFalse;
cristy01b7eb02009-09-10 23:10:14 +00002101 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002102 {
cristyaaa0cb62010-02-15 17:47:27 +00002103 LockSemaphoreInfo(cache_info->semaphore);
2104 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
cristy3ed852e2009-09-05 21:47:34 +00002105 {
cristyaaa0cb62010-02-15 17:47:27 +00002106 Image
2107 clone_image;
2108
2109 CacheInfo
2110 *clone_info;
2111
2112 /*
2113 Clone pixel cache.
2114 */
2115 clone_image=(*image);
cristy93505cf2010-08-10 21:37:49 +00002116 clone_image.semaphore=AllocateSemaphoreInfo();
2117 clone_image.reference_count=1;
cristyaaa0cb62010-02-15 17:47:27 +00002118 clone_image.cache=ClonePixelCache(cache_info);
2119 clone_info=(CacheInfo *) clone_image.cache;
cristyabd6e372010-09-15 19:11:26 +00002120 status=OpenPixelCache(&clone_image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00002121 if (status != MagickFalse)
2122 {
cristyabd6e372010-09-15 19:11:26 +00002123 if (clone != MagickFalse)
2124 status=ClonePixelCachePixels(clone_info,cache_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00002125 if (status != MagickFalse)
2126 {
cristyabd6e372010-09-15 19:11:26 +00002127 destroy=MagickTrue;
2128 image->cache=clone_image.cache;
cristy3ed852e2009-09-05 21:47:34 +00002129 }
2130 }
cristy93505cf2010-08-10 21:37:49 +00002131 DestroySemaphoreInfo(&clone_image.semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002132 }
cristyaaa0cb62010-02-15 17:47:27 +00002133 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002134 }
cristy4320e0e2009-09-10 15:00:08 +00002135 if (destroy != MagickFalse)
cristyf2e11662009-10-14 01:24:43 +00002136 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00002137 if (status != MagickFalse)
2138 {
2139 /*
2140 Ensure the image matches the pixel cache morphology.
2141 */
2142 image->taint=MagickTrue;
2143 image->type=UndefinedType;
cristydd438462010-05-06 13:44:04 +00002144 if (image->colorspace == GRAYColorspace)
2145 image->colorspace=RGBColorspace;
cristy3ed852e2009-09-05 21:47:34 +00002146 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2147 status=OpenPixelCache(image,IOMode,exception);
2148 }
cristyf84a1932010-01-03 18:00:18 +00002149 UnlockSemaphoreInfo(image->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002150 if (status == MagickFalse)
2151 return((Cache) NULL);
2152 return(image->cache);
2153}
2154
2155/*
2156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2157% %
2158% %
2159% %
2160% G e t O n e A u t h e n t i c P i x e l %
2161% %
2162% %
2163% %
2164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2165%
2166% GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2167% location. The image background color is returned if an error occurs.
2168%
2169% The format of the GetOneAuthenticPixel() method is:
2170%
cristybb503372010-05-27 20:51:26 +00002171% MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2172% const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002173%
2174% A description of each parameter follows:
2175%
2176% o image: the image.
2177%
2178% o x,y: These values define the location of the pixel to return.
2179%
2180% o pixel: return a pixel at the specified (x,y) location.
2181%
2182% o exception: return any errors or warnings in this structure.
2183%
2184*/
cristyacbbb7c2010-06-30 18:56:48 +00002185MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2186 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002187{
2188 CacheInfo
2189 *cache_info;
2190
2191 GetOneAuthenticPixelFromHandler
2192 get_one_authentic_pixel_from_handler;
2193
2194 MagickBooleanType
2195 status;
2196
2197 assert(image != (Image *) NULL);
2198 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002199 assert(image->cache != (Cache) NULL);
2200 cache_info=(CacheInfo *) image->cache;
2201 assert(cache_info->signature == MagickSignature);
2202 *pixel=image->background_color;
2203 get_one_authentic_pixel_from_handler=
2204 cache_info->methods.get_one_authentic_pixel_from_handler;
2205 if (get_one_authentic_pixel_from_handler ==
2206 (GetOneAuthenticPixelFromHandler) NULL)
2207 return(MagickFalse);
2208 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2209 pixel,exception);
2210 return(status);
2211}
2212
2213/*
2214%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2215% %
2216% %
2217% %
2218+ G e t O n e A u t h e n t i c P i x e l F r o m C a c h e %
2219% %
2220% %
2221% %
2222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2223%
2224% GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2225% location. The image background color is returned if an error occurs.
2226%
2227% The format of the GetOneAuthenticPixelFromCache() method is:
2228%
2229% MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
cristy5f959472010-05-27 22:19:46 +00002230% const ssize_t x,const ssize_t y,PixelPacket *pixel,
2231% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002232%
2233% A description of each parameter follows:
2234%
2235% o image: the image.
2236%
2237% o x,y: These values define the location of the pixel to return.
2238%
2239% o pixel: return a pixel at the specified (x,y) location.
2240%
2241% o exception: return any errors or warnings in this structure.
2242%
2243*/
2244static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
cristybb503372010-05-27 20:51:26 +00002245 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002246{
2247 PixelPacket
2248 *pixels;
2249
cristy3ed852e2009-09-05 21:47:34 +00002250 *pixel=image->background_color;
2251 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2252 if (pixels == (PixelPacket *) NULL)
2253 return(MagickFalse);
2254 *pixel=(*pixels);
2255 return(MagickTrue);
2256}
2257
2258/*
2259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2260% %
2261% %
2262% %
2263% G e t O n e V i r t u a l M a g i c k P i x e l %
2264% %
2265% %
2266% %
2267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2268%
2269% GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2270% location. The image background color is returned if an error occurs. If
2271% you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2272%
2273% The format of the GetOneVirtualMagickPixel() method is:
2274%
2275% MagickBooleanType GetOneVirtualMagickPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002276% const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
cristy3ed852e2009-09-05 21:47:34 +00002277% ExceptionInfo exception)
2278%
2279% A description of each parameter follows:
2280%
2281% o image: the image.
2282%
2283% o x,y: these values define the location of the pixel to return.
2284%
2285% o pixel: return a pixel at the specified (x,y) location.
2286%
2287% o exception: return any errors or warnings in this structure.
2288%
2289*/
2290MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
cristyacbbb7c2010-06-30 18:56:48 +00002291 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2292 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002293{
2294 CacheInfo
2295 *cache_info;
2296
2297 register const IndexPacket
2298 *indexes;
2299
2300 register const PixelPacket
2301 *p;
2302
2303 assert(image != (const Image *) NULL);
2304 assert(image->signature == MagickSignature);
2305 assert(image->cache != (Cache) NULL);
2306 cache_info=(CacheInfo *) image->cache;
2307 assert(cache_info->signature == MagickSignature);
2308 GetMagickPixelPacket(image,pixel);
2309 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2310 exception);
2311 if (p == (const PixelPacket *) NULL)
2312 return(MagickFalse);
2313 indexes=GetVirtualIndexQueue(image);
2314 SetMagickPixelPacket(image,p,indexes,pixel);
2315 return(MagickTrue);
2316}
2317
2318/*
2319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2320% %
2321% %
2322% %
2323% G e t O n e V i r t u a l M e t h o d P i x e l %
2324% %
2325% %
2326% %
2327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2328%
2329% GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2330% location as defined by specified pixel method. The image background color
2331% is returned if an error occurs. If you plan to modify the pixel, use
2332% GetOneAuthenticPixel() instead.
2333%
2334% The format of the GetOneVirtualMethodPixel() method is:
2335%
2336% MagickBooleanType GetOneVirtualMethodPixel(const Image image,
cristybb503372010-05-27 20:51:26 +00002337% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2338% const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002339%
2340% A description of each parameter follows:
2341%
2342% o image: the image.
2343%
2344% o virtual_pixel_method: the virtual pixel method.
2345%
2346% o x,y: These values define the location of the pixel to return.
2347%
2348% o pixel: return a pixel at the specified (x,y) location.
2349%
2350% o exception: return any errors or warnings in this structure.
2351%
2352*/
2353MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002354 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002355 PixelPacket *pixel,ExceptionInfo *exception)
2356{
2357 GetOneVirtualPixelFromHandler
2358 get_one_virtual_pixel_from_handler;
2359
2360 CacheInfo
2361 *cache_info;
2362
2363 MagickBooleanType
2364 status;
2365
2366 assert(image != (const Image *) NULL);
2367 assert(image->signature == MagickSignature);
2368 assert(image->cache != (Cache) NULL);
2369 cache_info=(CacheInfo *) image->cache;
2370 assert(cache_info->signature == MagickSignature);
2371 *pixel=image->background_color;
2372 get_one_virtual_pixel_from_handler=
2373 cache_info->methods.get_one_virtual_pixel_from_handler;
2374 if (get_one_virtual_pixel_from_handler ==
2375 (GetOneVirtualPixelFromHandler) NULL)
2376 return(MagickFalse);
2377 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2378 pixel,exception);
2379 return(status);
2380}
2381
2382/*
2383%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2384% %
2385% %
2386% %
2387% G e t O n e V i r t u a l P i x e l %
2388% %
2389% %
2390% %
2391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2392%
2393% GetOneVirtualPixel() returns a single virtual pixel at the specified
2394% (x,y) location. The image background color is returned if an error occurs.
2395% If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2396%
2397% The format of the GetOneVirtualPixel() method is:
2398%
cristybb503372010-05-27 20:51:26 +00002399% MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2400% const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
cristy3ed852e2009-09-05 21:47:34 +00002401%
2402% A description of each parameter follows:
2403%
2404% o image: the image.
2405%
2406% o x,y: These values define the location of the pixel to return.
2407%
2408% o pixel: return a pixel at the specified (x,y) location.
2409%
2410% o exception: return any errors or warnings in this structure.
2411%
2412*/
2413MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
cristybb503372010-05-27 20:51:26 +00002414 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002415{
2416 GetOneVirtualPixelFromHandler
2417 get_one_virtual_pixel_from_handler;
2418
2419 CacheInfo
2420 *cache_info;
2421
2422 MagickBooleanType
2423 status;
2424
2425 assert(image != (const Image *) NULL);
2426 assert(image->signature == MagickSignature);
2427 assert(image->cache != (Cache) NULL);
2428 cache_info=(CacheInfo *) image->cache;
2429 assert(cache_info->signature == MagickSignature);
2430 *pixel=image->background_color;
2431 get_one_virtual_pixel_from_handler=
2432 cache_info->methods.get_one_virtual_pixel_from_handler;
2433 if (get_one_virtual_pixel_from_handler ==
2434 (GetOneVirtualPixelFromHandler) NULL)
2435 return(MagickFalse);
2436 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2437 image),x,y,pixel,exception);
2438 return(status);
2439}
2440
2441/*
2442%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2443% %
2444% %
2445% %
2446+ G e t O n e V i r t u a l P i x e l F r o m C a c h e %
2447% %
2448% %
2449% %
2450%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2451%
2452% GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2453% specified (x,y) location. The image background color is returned if an
2454% error occurs.
2455%
2456% The format of the GetOneVirtualPixelFromCache() method is:
2457%
2458% MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
cristybb503372010-05-27 20:51:26 +00002459% const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002460% PixelPacket *pixel,ExceptionInfo *exception)
2461%
2462% A description of each parameter follows:
2463%
2464% o image: the image.
2465%
2466% o virtual_pixel_method: the virtual pixel method.
2467%
2468% o x,y: These values define the location of the pixel to return.
2469%
2470% o pixel: return a pixel at the specified (x,y) location.
2471%
2472% o exception: return any errors or warnings in this structure.
2473%
2474*/
2475static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00002476 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
cristy3ed852e2009-09-05 21:47:34 +00002477 PixelPacket *pixel,ExceptionInfo *exception)
2478{
2479 const PixelPacket
2480 *pixels;
2481
2482 *pixel=image->background_color;
2483 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2484 if (pixels == (const PixelPacket *) NULL)
2485 return(MagickFalse);
2486 *pixel=(*pixels);
2487 return(MagickTrue);
2488}
2489
2490/*
2491%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2492% %
2493% %
2494% %
2495+ G e t P i x e l C a c h e C o l o r s p a c e %
2496% %
2497% %
2498% %
2499%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2500%
2501% GetPixelCacheColorspace() returns the class type of the pixel cache.
2502%
2503% The format of the GetPixelCacheColorspace() method is:
2504%
2505% Colorspace GetPixelCacheColorspace(Cache cache)
2506%
2507% A description of each parameter follows:
2508%
2509% o cache: the pixel cache.
2510%
2511*/
2512MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2513{
2514 CacheInfo
2515 *cache_info;
2516
2517 assert(cache != (Cache) NULL);
2518 cache_info=(CacheInfo *) cache;
2519 assert(cache_info->signature == MagickSignature);
2520 if (cache_info->debug != MagickFalse)
2521 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2522 cache_info->filename);
2523 return(cache_info->colorspace);
2524}
2525
2526/*
2527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2528% %
2529% %
2530% %
2531+ G e t P i x e l C a c h e M e t h o d s %
2532% %
2533% %
2534% %
2535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2536%
2537% GetPixelCacheMethods() initializes the CacheMethods structure.
2538%
2539% The format of the GetPixelCacheMethods() method is:
2540%
2541% void GetPixelCacheMethods(CacheMethods *cache_methods)
2542%
2543% A description of each parameter follows:
2544%
2545% o cache_methods: Specifies a pointer to a CacheMethods structure.
2546%
2547*/
2548MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2549{
2550 assert(cache_methods != (CacheMethods *) NULL);
2551 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2552 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2553 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2554 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2555 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2556 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2557 cache_methods->get_authentic_indexes_from_handler=
2558 GetAuthenticIndexesFromCache;
2559 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2560 cache_methods->get_one_authentic_pixel_from_handler=
2561 GetOneAuthenticPixelFromCache;
2562 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2563 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2564 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2565}
2566
2567/*
2568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2569% %
2570% %
2571% %
2572+ G e t P i x e l C a c h e N e x u s E x t e n t %
2573% %
2574% %
2575% %
2576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2577%
2578% GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2579% the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2580%
2581% The format of the GetPixelCacheNexusExtent() method is:
2582%
2583% MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2584% NexusInfo *nexus_info)
2585%
2586% A description of each parameter follows:
2587%
2588% o nexus_info: the nexus info.
2589%
2590*/
2591MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2592 NexusInfo *nexus_info)
2593{
2594 CacheInfo
2595 *cache_info;
2596
2597 MagickSizeType
2598 extent;
2599
2600 if (cache == (Cache) NULL)
2601 return(0);
2602 cache_info=(CacheInfo *) cache;
2603 assert(cache_info->signature == MagickSignature);
2604 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2605 if (extent == 0)
2606 return((MagickSizeType) cache_info->columns*cache_info->rows);
2607 return(extent);
2608}
2609
2610/*
2611%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2612% %
2613% %
2614% %
2615+ G e t P i x e l C a c h e N e x u s I n d e x e s %
2616% %
2617% %
2618% %
2619%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2620%
2621% GetPixelCacheNexusIndexes() returns the indexes associated with the
2622% specified cache nexus.
2623%
2624% The format of the GetPixelCacheNexusIndexes() method is:
2625%
2626% IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2627% NexusInfo *nexus_info)
2628%
2629% A description of each parameter follows:
2630%
2631% o cache: the pixel cache.
2632%
2633% o nexus_info: the cache nexus to return the colormap indexes.
2634%
2635*/
2636MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2637 NexusInfo *nexus_info)
2638{
2639 CacheInfo
2640 *cache_info;
2641
2642 if (cache == (Cache) NULL)
2643 return((IndexPacket *) NULL);
2644 cache_info=(CacheInfo *) cache;
2645 assert(cache_info->signature == MagickSignature);
2646 if (cache_info->storage_class == UndefinedClass)
2647 return((IndexPacket *) NULL);
2648 return(nexus_info->indexes);
2649}
2650
2651/*
2652%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2653% %
2654% %
2655% %
2656+ G e t P i x e l C a c h e N e x u s P i x e l s %
2657% %
2658% %
2659% %
2660%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2661%
2662% GetPixelCacheNexusPixels() returns the pixels associated with the specified
2663% cache nexus.
2664%
2665% The format of the GetPixelCacheNexusPixels() method is:
2666%
2667% PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2668% NexusInfo *nexus_info)
2669%
2670% A description of each parameter follows:
2671%
2672% o cache: the pixel cache.
2673%
2674% o nexus_info: the cache nexus to return the pixels.
2675%
2676*/
2677MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2678 NexusInfo *nexus_info)
2679{
2680 CacheInfo
2681 *cache_info;
2682
2683 if (cache == (Cache) NULL)
2684 return((PixelPacket *) NULL);
2685 cache_info=(CacheInfo *) cache;
2686 assert(cache_info->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002687 if (cache_info->storage_class == UndefinedClass)
2688 return((PixelPacket *) NULL);
2689 return(nexus_info->pixels);
2690}
2691
2692/*
2693%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2694% %
2695% %
2696% %
cristy056ba772010-01-02 23:33:54 +00002697+ G e t P i x e l C a c h e P i x e l s %
2698% %
2699% %
2700% %
2701%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2702%
2703% GetPixelCachePixels() returns the pixels associated with the specified image.
2704%
2705% The format of the GetPixelCachePixels() method is:
2706%
cristyf84a1932010-01-03 18:00:18 +00002707% void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2708% ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002709%
2710% A description of each parameter follows:
2711%
2712% o image: the image.
2713%
2714% o length: the pixel cache length.
2715%
cristyf84a1932010-01-03 18:00:18 +00002716% o exception: return any errors or warnings in this structure.
2717%
cristy056ba772010-01-02 23:33:54 +00002718*/
cristyf84a1932010-01-03 18:00:18 +00002719MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2720 ExceptionInfo *exception)
cristy056ba772010-01-02 23:33:54 +00002721{
2722 CacheInfo
2723 *cache_info;
2724
2725 assert(image != (const Image *) NULL);
2726 assert(image->signature == MagickSignature);
cristy056ba772010-01-02 23:33:54 +00002727 assert(image->cache != (Cache) NULL);
cristy77ff0282010-09-13 00:51:10 +00002728 cache_info=(CacheInfo *) image->cache;
cristy056ba772010-01-02 23:33:54 +00002729 assert(cache_info->signature == MagickSignature);
2730 *length=0;
cristyc4c8d132010-01-07 01:58:38 +00002731 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
cristy056ba772010-01-02 23:33:54 +00002732 return((void *) NULL);
2733 *length=cache_info->length;
2734 return((void *) cache_info->pixels);
2735}
2736
2737/*
2738%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2739% %
2740% %
2741% %
cristyb32b90a2009-09-07 21:45:48 +00002742+ G e t P i x e l C a c h e S t o r a g e C l a s s %
cristy3ed852e2009-09-05 21:47:34 +00002743% %
2744% %
2745% %
2746%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2747%
2748% GetPixelCacheStorageClass() returns the class type of the pixel cache.
2749%
2750% The format of the GetPixelCacheStorageClass() method is:
2751%
2752% ClassType GetPixelCacheStorageClass(Cache cache)
2753%
2754% A description of each parameter follows:
2755%
2756% o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2757%
2758% o cache: the pixel cache.
2759%
2760*/
2761MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2762{
2763 CacheInfo
2764 *cache_info;
2765
2766 assert(cache != (Cache) NULL);
2767 cache_info=(CacheInfo *) cache;
2768 assert(cache_info->signature == MagickSignature);
2769 if (cache_info->debug != MagickFalse)
2770 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2771 cache_info->filename);
2772 return(cache_info->storage_class);
2773}
2774
2775/*
2776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2777% %
2778% %
2779% %
cristyb32b90a2009-09-07 21:45:48 +00002780+ G e t P i x e l C a c h e T i l e S i z e %
2781% %
2782% %
2783% %
2784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2785%
2786% GetPixelCacheTileSize() returns the pixel cache tile size.
2787%
2788% The format of the GetPixelCacheTileSize() method is:
2789%
cristybb503372010-05-27 20:51:26 +00002790% void GetPixelCacheTileSize(const Image *image,size_t *width,
2791% size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002792%
2793% A description of each parameter follows:
2794%
2795% o image: the image.
2796%
2797% o width: the optimize cache tile width in pixels.
2798%
2799% o height: the optimize cache tile height in pixels.
2800%
2801*/
cristybb503372010-05-27 20:51:26 +00002802MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2803 size_t *height)
cristyb32b90a2009-09-07 21:45:48 +00002804{
2805 CacheInfo
2806 *cache_info;
2807
2808 assert(image != (Image *) NULL);
2809 assert(image->signature == MagickSignature);
2810 if (image->debug != MagickFalse)
2811 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2812 assert(image->cache != (Cache) NULL);
2813 cache_info=(CacheInfo *) image->cache;
2814 assert(cache_info->signature == MagickSignature);
2815 *width=2048UL/sizeof(PixelPacket);
2816 if (GetPixelCacheType(image) == DiskCache)
cristydaa97692009-09-13 02:10:35 +00002817 *width=8192UL/sizeof(PixelPacket);
cristyb32b90a2009-09-07 21:45:48 +00002818 *height=(*width);
2819}
2820
2821/*
2822%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2823% %
2824% %
2825% %
2826+ G e t P i x e l C a c h e T y p e %
2827% %
2828% %
2829% %
2830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2831%
2832% GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2833%
2834% The format of the GetPixelCacheType() method is:
2835%
2836% CacheType GetPixelCacheType(const Image *image)
2837%
2838% A description of each parameter follows:
2839%
2840% o image: the image.
2841%
2842*/
2843MagickExport CacheType GetPixelCacheType(const Image *image)
2844{
2845 CacheInfo
2846 *cache_info;
2847
2848 assert(image != (Image *) NULL);
2849 assert(image->signature == MagickSignature);
cristyb32b90a2009-09-07 21:45:48 +00002850 assert(image->cache != (Cache) NULL);
2851 cache_info=(CacheInfo *) image->cache;
2852 assert(cache_info->signature == MagickSignature);
2853 return(cache_info->type);
2854}
2855
2856/*
2857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2858% %
2859% %
2860% %
cristy3ed852e2009-09-05 21:47:34 +00002861+ G e t P i x e l C a c h e V i r t u a l M e t h o d %
2862% %
2863% %
2864% %
2865%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2866%
2867% GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2868% pixel cache. A virtual pixel is any pixel access that is outside the
2869% boundaries of the image cache.
2870%
2871% The format of the GetPixelCacheVirtualMethod() method is:
2872%
2873% VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2874%
2875% A description of each parameter follows:
2876%
2877% o image: the image.
2878%
2879*/
2880MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2881{
2882 CacheInfo
2883 *cache_info;
2884
2885 assert(image != (Image *) NULL);
2886 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00002887 assert(image->cache != (Cache) NULL);
2888 cache_info=(CacheInfo *) image->cache;
2889 assert(cache_info->signature == MagickSignature);
2890 return(cache_info->virtual_pixel_method);
2891}
2892
2893/*
2894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2895% %
2896% %
2897% %
2898+ G e t V i r t u a l I n d e x e s F r o m C a c h e %
2899% %
2900% %
2901% %
2902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2903%
2904% GetVirtualIndexesFromCache() returns the indexes associated with the last
2905% call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2906%
2907% The format of the GetVirtualIndexesFromCache() method is:
2908%
2909% IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2910%
2911% A description of each parameter follows:
2912%
2913% o image: the image.
2914%
2915*/
2916static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2917{
2918 CacheInfo
2919 *cache_info;
2920
2921 const IndexPacket
2922 *indexes;
2923
cristy6ebe97c2010-07-03 01:17:28 +00002924 int
cristy3ed852e2009-09-05 21:47:34 +00002925 id;
2926
cristy3ed852e2009-09-05 21:47:34 +00002927 cache_info=(CacheInfo *) image->cache;
2928 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00002929 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00002930 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
2931 return(indexes);
2932}
2933
2934/*
2935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2936% %
2937% %
2938% %
2939+ G e t V i r t u a l I n d e x e s F r o m N e x u s %
2940% %
2941% %
2942% %
2943%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2944%
2945% GetVirtualIndexesFromNexus() returns the indexes associated with the
2946% specified cache nexus.
2947%
2948% The format of the GetVirtualIndexesFromNexus() method is:
2949%
2950% const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2951% NexusInfo *nexus_info)
2952%
2953% A description of each parameter follows:
2954%
2955% o cache: the pixel cache.
2956%
2957% o nexus_info: the cache nexus to return the colormap indexes.
2958%
2959*/
2960MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2961 NexusInfo *nexus_info)
2962{
2963 CacheInfo
2964 *cache_info;
2965
2966 if (cache == (Cache) NULL)
2967 return((IndexPacket *) NULL);
2968 cache_info=(CacheInfo *) cache;
2969 assert(cache_info->signature == MagickSignature);
2970 if (cache_info->storage_class == UndefinedClass)
2971 return((IndexPacket *) NULL);
2972 return(nexus_info->indexes);
2973}
2974
2975/*
2976%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2977% %
2978% %
2979% %
2980% G e t V i r t u a l I n d e x Q u e u e %
2981% %
2982% %
2983% %
2984%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2985%
2986% GetVirtualIndexQueue() returns the virtual black channel or the
2987% colormap indexes associated with the last call to QueueAuthenticPixels() or
2988% GetVirtualPixels(). NULL is returned if the black channel or colormap
2989% indexes are not available.
2990%
2991% The format of the GetVirtualIndexQueue() method is:
2992%
2993% const IndexPacket *GetVirtualIndexQueue(const Image *image)
2994%
2995% A description of each parameter follows:
2996%
2997% o image: the image.
2998%
2999*/
3000MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3001{
3002 CacheInfo
3003 *cache_info;
3004
3005 assert(image != (const Image *) NULL);
3006 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003007 assert(image->cache != (Cache) NULL);
3008 cache_info=(CacheInfo *) image->cache;
3009 assert(cache_info->signature == MagickSignature);
3010 if (cache_info->methods.get_virtual_indexes_from_handler ==
3011 (GetVirtualIndexesFromHandler) NULL)
3012 return((IndexPacket *) NULL);
3013 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3014}
3015
3016/*
3017%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3018% %
3019% %
3020% %
3021+ G e t V i r t u a l P i x e l s F r o m N e x u s %
3022% %
3023% %
3024% %
3025%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3026%
3027% GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3028% pixel cache as defined by the geometry parameters. A pointer to the pixels
3029% is returned if the pixels are transferred, otherwise a NULL is returned.
3030%
3031% The format of the GetVirtualPixelsFromNexus() method is:
3032%
3033% PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003034% const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
cristy5f959472010-05-27 22:19:46 +00003035% const size_t columns,const size_t rows,NexusInfo *nexus_info,
3036% ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003037%
3038% A description of each parameter follows:
3039%
3040% o image: the image.
3041%
3042% o virtual_pixel_method: the virtual pixel method.
3043%
3044% o x,y,columns,rows: These values define the perimeter of a region of
3045% pixels.
3046%
3047% o nexus_info: the cache nexus to acquire.
3048%
3049% o exception: return any errors or warnings in this structure.
3050%
3051*/
3052
cristybb503372010-05-27 20:51:26 +00003053static ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003054 DitherMatrix[64] =
3055 {
3056 0, 48, 12, 60, 3, 51, 15, 63,
3057 32, 16, 44, 28, 35, 19, 47, 31,
3058 8, 56, 4, 52, 11, 59, 7, 55,
3059 40, 24, 36, 20, 43, 27, 39, 23,
3060 2, 50, 14, 62, 1, 49, 13, 61,
3061 34, 18, 46, 30, 33, 17, 45, 29,
3062 10, 58, 6, 54, 9, 57, 5, 53,
3063 42, 26, 38, 22, 41, 25, 37, 21
3064 };
3065
cristybb503372010-05-27 20:51:26 +00003066static inline ssize_t DitherX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003067{
cristybb503372010-05-27 20:51:26 +00003068 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003069 index;
3070
3071 index=x+DitherMatrix[x & 0x07]-32L;
3072 if (index < 0L)
3073 return(0L);
cristybb503372010-05-27 20:51:26 +00003074 if (index >= (ssize_t) columns)
3075 return((ssize_t) columns-1L);
cristy3ed852e2009-09-05 21:47:34 +00003076 return(index);
3077}
3078
cristybb503372010-05-27 20:51:26 +00003079static inline ssize_t DitherY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003080{
cristybb503372010-05-27 20:51:26 +00003081 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003082 index;
3083
3084 index=y+DitherMatrix[y & 0x07]-32L;
3085 if (index < 0L)
3086 return(0L);
cristybb503372010-05-27 20:51:26 +00003087 if (index >= (ssize_t) rows)
3088 return((ssize_t) rows-1L);
cristy3ed852e2009-09-05 21:47:34 +00003089 return(index);
3090}
3091
cristybb503372010-05-27 20:51:26 +00003092static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003093{
3094 if (x < 0L)
3095 return(0L);
cristybb503372010-05-27 20:51:26 +00003096 if (x >= (ssize_t) columns)
3097 return((ssize_t) (columns-1));
cristy3ed852e2009-09-05 21:47:34 +00003098 return(x);
3099}
3100
cristybb503372010-05-27 20:51:26 +00003101static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003102{
3103 if (y < 0L)
3104 return(0L);
cristybb503372010-05-27 20:51:26 +00003105 if (y >= (ssize_t) rows)
3106 return((ssize_t) (rows-1));
cristy3ed852e2009-09-05 21:47:34 +00003107 return(y);
3108}
3109
cristybb503372010-05-27 20:51:26 +00003110static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
cristy3ed852e2009-09-05 21:47:34 +00003111{
cristybb503372010-05-27 20:51:26 +00003112 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003113}
3114
cristybb503372010-05-27 20:51:26 +00003115static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
cristy3ed852e2009-09-05 21:47:34 +00003116{
cristybb503372010-05-27 20:51:26 +00003117 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
cristy3ed852e2009-09-05 21:47:34 +00003118}
3119
3120/*
3121 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3122 returns not only the quotient (tile the offset falls in) but also the positive
3123 remainer within that tile such that 0 <= remainder < extent. This method is
3124 essentially a ldiv() using a floored modulo division rather than the normal
3125 default truncated modulo division.
3126*/
cristybb503372010-05-27 20:51:26 +00003127static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3128 const size_t extent)
cristy3ed852e2009-09-05 21:47:34 +00003129{
3130 MagickModulo
3131 modulo;
3132
cristybb503372010-05-27 20:51:26 +00003133 modulo.quotient=offset/(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003134 if (offset < 0L)
3135 modulo.quotient--;
cristybb503372010-05-27 20:51:26 +00003136 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
cristy3ed852e2009-09-05 21:47:34 +00003137 return(modulo);
3138}
3139
3140MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
cristybb503372010-05-27 20:51:26 +00003141 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3142 const size_t columns,const size_t rows,NexusInfo *nexus_info,
cristy3ed852e2009-09-05 21:47:34 +00003143 ExceptionInfo *exception)
3144{
3145 CacheInfo
3146 *cache_info;
3147
cristyc3ec0d42010-04-07 01:18:08 +00003148 IndexPacket
3149 virtual_index;
3150
cristy3ed852e2009-09-05 21:47:34 +00003151 MagickOffsetType
3152 offset;
3153
3154 MagickSizeType
3155 length,
3156 number_pixels;
3157
3158 NexusInfo
3159 **virtual_nexus;
3160
3161 PixelPacket
3162 *pixels,
3163 virtual_pixel;
3164
3165 RectangleInfo
3166 region;
3167
3168 register const IndexPacket
cristyc3ec0d42010-04-07 01:18:08 +00003169 *restrict virtual_indexes;
cristy3ed852e2009-09-05 21:47:34 +00003170
3171 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003172 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003173
3174 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003175 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003176
cristye076a6e2010-08-15 19:59:43 +00003177 register PixelPacket
3178 *restrict q;
3179
cristybb503372010-05-27 20:51:26 +00003180 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003181 u,
3182 v;
3183
cristy3ed852e2009-09-05 21:47:34 +00003184 /*
3185 Acquire pixels.
3186 */
cristy3ed852e2009-09-05 21:47:34 +00003187 cache_info=(CacheInfo *) image->cache;
cristy4cfbb3f2010-03-14 20:40:23 +00003188 if (cache_info->type == UndefinedCache)
cristy3ed852e2009-09-05 21:47:34 +00003189 return((const PixelPacket *) NULL);
3190 region.x=x;
3191 region.y=y;
3192 region.width=columns;
3193 region.height=rows;
3194 pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3195 if (pixels == (PixelPacket *) NULL)
3196 return((const PixelPacket *) NULL);
cristydf415c82010-03-11 16:47:50 +00003197 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3198 nexus_info->region.x;
3199 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3200 nexus_info->region.width-1L;
cristy3ed852e2009-09-05 21:47:34 +00003201 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3202 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
cristybb503372010-05-27 20:51:26 +00003203 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3204 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003205 {
3206 MagickBooleanType
3207 status;
3208
3209 /*
3210 Pixel request is inside cache extents.
3211 */
3212 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3213 return(pixels);
3214 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3215 if (status == MagickFalse)
3216 return((const PixelPacket *) NULL);
3217 if ((cache_info->storage_class == PseudoClass) ||
3218 (cache_info->colorspace == CMYKColorspace))
3219 {
3220 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3221 if (status == MagickFalse)
3222 return((const PixelPacket *) NULL);
3223 }
3224 return(pixels);
3225 }
3226 /*
3227 Pixel request is outside cache extents.
3228 */
3229 q=pixels;
3230 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3231 virtual_nexus=AcquirePixelCacheNexus(1);
3232 if (virtual_nexus == (NexusInfo **) NULL)
3233 {
3234 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3235 "UnableToGetCacheNexus","`%s'",image->filename);
3236 return((const PixelPacket *) NULL);
3237 }
3238 switch (virtual_pixel_method)
3239 {
3240 case BlackVirtualPixelMethod:
3241 {
cristy4789f0d2010-01-10 00:01:06 +00003242 SetRedPixelComponent(&virtual_pixel,0);
3243 SetGreenPixelComponent(&virtual_pixel,0);
3244 SetBluePixelComponent(&virtual_pixel,0);
3245 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003246 break;
3247 }
3248 case GrayVirtualPixelMethod:
3249 {
cristy4789f0d2010-01-10 00:01:06 +00003250 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3251 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3252 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3253 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003254 break;
3255 }
3256 case TransparentVirtualPixelMethod:
3257 {
cristy4789f0d2010-01-10 00:01:06 +00003258 SetRedPixelComponent(&virtual_pixel,0);
3259 SetGreenPixelComponent(&virtual_pixel,0);
3260 SetBluePixelComponent(&virtual_pixel,0);
3261 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003262 break;
3263 }
3264 case MaskVirtualPixelMethod:
3265 case WhiteVirtualPixelMethod:
3266 {
cristy4789f0d2010-01-10 00:01:06 +00003267 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3268 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3269 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3270 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
cristy3ed852e2009-09-05 21:47:34 +00003271 break;
3272 }
3273 default:
3274 {
3275 virtual_pixel=image->background_color;
3276 break;
3277 }
3278 }
cristyc3ec0d42010-04-07 01:18:08 +00003279 virtual_index=0;
cristybb503372010-05-27 20:51:26 +00003280 for (v=0; v < (ssize_t) rows; v++)
cristy3ed852e2009-09-05 21:47:34 +00003281 {
cristybb503372010-05-27 20:51:26 +00003282 for (u=0; u < (ssize_t) columns; u+=length)
cristy3ed852e2009-09-05 21:47:34 +00003283 {
3284 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
cristybb503372010-05-27 20:51:26 +00003285 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
cristy30097232010-07-01 02:16:30 +00003286 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3287 (length == 0))
cristy3ed852e2009-09-05 21:47:34 +00003288 {
3289 MagickModulo
3290 x_modulo,
3291 y_modulo;
3292
3293 /*
3294 Transfer a single pixel.
3295 */
3296 length=(MagickSizeType) 1;
3297 switch (virtual_pixel_method)
3298 {
3299 case BackgroundVirtualPixelMethod:
3300 case ConstantVirtualPixelMethod:
3301 case BlackVirtualPixelMethod:
3302 case GrayVirtualPixelMethod:
3303 case TransparentVirtualPixelMethod:
3304 case MaskVirtualPixelMethod:
3305 case WhiteVirtualPixelMethod:
3306 {
3307 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003308 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003309 break;
3310 }
3311 case EdgeVirtualPixelMethod:
3312 default:
3313 {
3314 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003315 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003316 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003317 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3318 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003319 break;
3320 }
3321 case RandomVirtualPixelMethod:
3322 {
3323 if (cache_info->random_info == (RandomInfo *) NULL)
3324 cache_info->random_info=AcquireRandomInfo();
3325 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003326 RandomX(cache_info->random_info,cache_info->columns),
3327 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003328 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003329 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3330 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003331 break;
3332 }
3333 case DitherVirtualPixelMethod:
3334 {
3335 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003336 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
cristy3ed852e2009-09-05 21:47:34 +00003337 1UL,1UL,virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003338 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3339 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003340 break;
3341 }
3342 case TileVirtualPixelMethod:
3343 {
3344 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3345 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3346 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3347 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3348 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003349 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3350 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003351 break;
3352 }
3353 case MirrorVirtualPixelMethod:
3354 {
3355 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3356 if ((x_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003357 x_modulo.remainder=(ssize_t) cache_info->columns-
cristy3ed852e2009-09-05 21:47:34 +00003358 x_modulo.remainder-1L;
3359 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3360 if ((y_modulo.quotient & 0x01) == 1L)
cristybb503372010-05-27 20:51:26 +00003361 y_modulo.remainder=(ssize_t) cache_info->rows-
cristy3ed852e2009-09-05 21:47:34 +00003362 y_modulo.remainder-1L;
3363 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3364 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3365 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003366 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3367 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003368 break;
3369 }
3370 case CheckerTileVirtualPixelMethod:
3371 {
3372 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3373 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3374 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3375 {
3376 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003377 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003378 break;
3379 }
3380 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3381 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3382 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003383 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3384 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003385 break;
3386 }
3387 case HorizontalTileVirtualPixelMethod:
3388 {
cristybb503372010-05-27 20:51:26 +00003389 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00003390 {
3391 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003392 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003393 break;
3394 }
3395 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3396 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3397 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3398 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3399 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003400 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3401 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003402 break;
3403 }
3404 case VerticalTileVirtualPixelMethod:
3405 {
cristybb503372010-05-27 20:51:26 +00003406 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
cristy3ed852e2009-09-05 21:47:34 +00003407 {
3408 p=(&virtual_pixel);
cristyc3ec0d42010-04-07 01:18:08 +00003409 virtual_indexes=(&virtual_index);
cristy3ed852e2009-09-05 21:47:34 +00003410 break;
3411 }
3412 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3413 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3414 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3415 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3416 exception);
cristyc3ec0d42010-04-07 01:18:08 +00003417 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3418 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003419 break;
3420 }
3421 case HorizontalTileEdgeVirtualPixelMethod:
3422 {
3423 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3424 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003425 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003426 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003427 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3428 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003429 break;
3430 }
3431 case VerticalTileEdgeVirtualPixelMethod:
3432 {
3433 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3434 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
cristy222528c2010-01-09 23:36:34 +00003435 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
cristy3ed852e2009-09-05 21:47:34 +00003436 virtual_nexus[0],exception);
cristyc3ec0d42010-04-07 01:18:08 +00003437 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3438 virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003439 break;
3440 }
3441 }
3442 if (p == (const PixelPacket *) NULL)
3443 break;
3444 *q++=(*p);
cristyc3ec0d42010-04-07 01:18:08 +00003445 if ((indexes != (IndexPacket *) NULL) &&
3446 (virtual_indexes != (const IndexPacket *) NULL))
3447 *indexes++=(*virtual_indexes);
cristy3ed852e2009-09-05 21:47:34 +00003448 continue;
3449 }
3450 /*
3451 Transfer a run of pixels.
3452 */
3453 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
cristybb503372010-05-27 20:51:26 +00003454 (size_t) length,1UL,virtual_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003455 if (p == (const PixelPacket *) NULL)
3456 break;
cristyc3ec0d42010-04-07 01:18:08 +00003457 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
cristy3ed852e2009-09-05 21:47:34 +00003458 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3459 q+=length;
cristyc3ec0d42010-04-07 01:18:08 +00003460 if ((indexes != (IndexPacket *) NULL) &&
3461 (virtual_indexes != (const IndexPacket *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00003462 {
cristyc3ec0d42010-04-07 01:18:08 +00003463 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3464 sizeof(*virtual_indexes));
3465 indexes+=length;
cristy3ed852e2009-09-05 21:47:34 +00003466 }
3467 }
3468 }
3469 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3470 return(pixels);
3471}
3472
3473/*
3474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3475% %
3476% %
3477% %
3478+ G e t V i r t u a l P i x e l C a c h e %
3479% %
3480% %
3481% %
3482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3483%
3484% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3485% cache as defined by the geometry parameters. A pointer to the pixels
3486% is returned if the pixels are transferred, otherwise a NULL is returned.
3487%
3488% The format of the GetVirtualPixelCache() method is:
3489%
3490% const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003491% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3492% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003493% ExceptionInfo *exception)
3494%
3495% A description of each parameter follows:
3496%
3497% o image: the image.
3498%
3499% o virtual_pixel_method: the virtual pixel method.
3500%
3501% o x,y,columns,rows: These values define the perimeter of a region of
3502% pixels.
3503%
3504% o exception: return any errors or warnings in this structure.
3505%
3506*/
3507static const PixelPacket *GetVirtualPixelCache(const Image *image,
cristybb503372010-05-27 20:51:26 +00003508 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3509 const size_t columns,const size_t rows,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003510{
3511 CacheInfo
3512 *cache_info;
3513
3514 const PixelPacket
3515 *pixels;
3516
cristy6ebe97c2010-07-03 01:17:28 +00003517 int
cristy3ed852e2009-09-05 21:47:34 +00003518 id;
3519
cristy3ed852e2009-09-05 21:47:34 +00003520 cache_info=(CacheInfo *) image->cache;
3521 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003522 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003523 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3524 cache_info->nexus_info[id],exception);
3525 return(pixels);
3526}
3527
3528/*
3529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3530% %
3531% %
3532% %
3533% G e t V i r t u a l P i x e l Q u e u e %
3534% %
3535% %
3536% %
3537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3538%
3539% GetVirtualPixelQueue() returns the virtual pixels associated with the
3540% last call to QueueAuthenticPixels() or GetVirtualPixels().
3541%
3542% The format of the GetVirtualPixelQueue() method is:
3543%
3544% const PixelPacket *GetVirtualPixelQueue(const Image image)
3545%
3546% A description of each parameter follows:
3547%
3548% o image: the image.
3549%
3550*/
3551MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3552{
3553 CacheInfo
3554 *cache_info;
3555
3556 assert(image != (const Image *) NULL);
3557 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003558 assert(image->cache != (Cache) NULL);
3559 cache_info=(CacheInfo *) image->cache;
3560 assert(cache_info->signature == MagickSignature);
3561 if (cache_info->methods.get_virtual_pixels_handler ==
3562 (GetVirtualPixelsHandler) NULL)
3563 return((PixelPacket *) NULL);
3564 return(cache_info->methods.get_virtual_pixels_handler(image));
3565}
3566
3567/*
3568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3569% %
3570% %
3571% %
3572% G e t V i r t u a l P i x e l s %
3573% %
3574% %
3575% %
3576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3577%
3578% GetVirtualPixels() returns an immutable pixel region. If the
3579% region is successfully accessed, a pointer to it is returned, otherwise
cristyad4e5b22010-01-10 00:04:19 +00003580% NULL is returned. The returned pointer may point to a temporary working
cristy3ed852e2009-09-05 21:47:34 +00003581% copy of the pixels or it may point to the original pixels in memory.
3582% Performance is maximized if the selected region is part of one row, or one
3583% or more full rows, since there is opportunity to access the pixels in-place
cristyad4e5b22010-01-10 00:04:19 +00003584% (without a copy) if the image is in memory, or in a memory-mapped file. The
3585% returned pointer must *never* be deallocated by the user.
cristy3ed852e2009-09-05 21:47:34 +00003586%
3587% Pixels accessed via the returned pointer represent a simple array of type
3588% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3589% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3590% the black color component or to obtain the colormap indexes (of type
3591% IndexPacket) corresponding to the region.
3592%
3593% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3594%
3595% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3596% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3597% GetCacheViewAuthenticPixels() instead.
3598%
3599% The format of the GetVirtualPixels() method is:
3600%
cristybb503372010-05-27 20:51:26 +00003601% const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3602% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00003603% ExceptionInfo *exception)
3604%
3605% A description of each parameter follows:
3606%
3607% o image: the image.
3608%
3609% o x,y,columns,rows: These values define the perimeter of a region of
3610% pixels.
3611%
3612% o exception: return any errors or warnings in this structure.
3613%
3614*/
3615MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
cristy30097232010-07-01 02:16:30 +00003616 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3617 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003618{
3619 CacheInfo
3620 *cache_info;
3621
3622 const PixelPacket
3623 *pixels;
3624
3625 assert(image != (const Image *) NULL);
3626 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00003627 assert(image->cache != (Cache) NULL);
3628 cache_info=(CacheInfo *) image->cache;
3629 assert(cache_info->signature == MagickSignature);
3630 if (cache_info->methods.get_virtual_pixel_handler ==
3631 (GetVirtualPixelHandler) NULL)
3632 return((const PixelPacket *) NULL);
3633 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3634 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3635 return(pixels);
3636}
3637
3638/*
3639%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3640% %
3641% %
3642% %
3643+ G e t V i r t u a l P i x e l s F r o m C a c h e %
3644% %
3645% %
3646% %
3647%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3648%
3649% GetVirtualPixelsCache() returns the pixels associated with the last call
3650% to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3651%
3652% The format of the GetVirtualPixelsCache() method is:
3653%
3654% PixelPacket *GetVirtualPixelsCache(const Image *image)
3655%
3656% A description of each parameter follows:
3657%
3658% o image: the image.
3659%
3660*/
3661static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3662{
3663 CacheInfo
3664 *cache_info;
3665
3666 const PixelPacket
3667 *pixels;
3668
cristy6ebe97c2010-07-03 01:17:28 +00003669 int
cristy3ed852e2009-09-05 21:47:34 +00003670 id;
3671
cristy3ed852e2009-09-05 21:47:34 +00003672 cache_info=(CacheInfo *) image->cache;
3673 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00003674 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00003675 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3676 return(pixels);
3677}
3678
3679/*
3680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3681% %
3682% %
3683% %
3684+ G e t V i r t u a l P i x e l s N e x u s %
3685% %
3686% %
3687% %
3688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3689%
3690% GetVirtualPixelsNexus() returns the pixels associated with the specified
3691% cache nexus.
3692%
3693% The format of the GetVirtualPixelsNexus() method is:
3694%
3695% const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3696% NexusInfo *nexus_info)
3697%
3698% A description of each parameter follows:
3699%
3700% o cache: the pixel cache.
3701%
3702% o nexus_info: the cache nexus to return the colormap pixels.
3703%
3704*/
3705MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3706 NexusInfo *nexus_info)
3707{
3708 CacheInfo
3709 *cache_info;
3710
3711 if (cache == (Cache) NULL)
3712 return((PixelPacket *) NULL);
3713 cache_info=(CacheInfo *) cache;
3714 assert(cache_info->signature == MagickSignature);
3715 if (cache_info->storage_class == UndefinedClass)
3716 return((PixelPacket *) NULL);
3717 return((const PixelPacket *) nexus_info->pixels);
3718}
3719
3720/*
3721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3722% %
3723% %
3724% %
3725+ M a s k P i x e l C a c h e N e x u s %
3726% %
3727% %
3728% %
3729%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3730%
3731% MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3732% The method returns MagickTrue if the pixel region is masked, otherwise
3733% MagickFalse.
3734%
3735% The format of the MaskPixelCacheNexus() method is:
3736%
3737% MagickBooleanType MaskPixelCacheNexus(Image *image,
3738% NexusInfo *nexus_info,ExceptionInfo *exception)
3739%
3740% A description of each parameter follows:
3741%
3742% o image: the image.
3743%
3744% o nexus_info: the cache nexus to clip.
3745%
3746% o exception: return any errors or warnings in this structure.
3747%
3748*/
3749
3750static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3751 const MagickRealType alpha,const MagickPixelPacket *q,
3752 const MagickRealType beta,MagickPixelPacket *composite)
3753{
3754 MagickRealType
3755 gamma;
3756
3757 if (alpha == TransparentOpacity)
3758 {
3759 *composite=(*q);
3760 return;
3761 }
3762 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3763 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3764 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3765 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3766 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3767 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3768 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3769}
3770
3771static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3772 ExceptionInfo *exception)
3773{
3774 CacheInfo
3775 *cache_info;
3776
3777 MagickPixelPacket
3778 alpha,
3779 beta;
3780
3781 MagickSizeType
3782 number_pixels;
3783
3784 NexusInfo
3785 **clip_nexus,
3786 **image_nexus;
3787
3788 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003789 *restrict r;
cristy3ed852e2009-09-05 21:47:34 +00003790
3791 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00003792 *restrict nexus_indexes,
3793 *restrict indexes;
cristy3ed852e2009-09-05 21:47:34 +00003794
cristy3ed852e2009-09-05 21:47:34 +00003795 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00003796 *restrict p,
3797 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00003798
cristye076a6e2010-08-15 19:59:43 +00003799 register ssize_t
3800 i;
3801
cristy3ed852e2009-09-05 21:47:34 +00003802 /*
3803 Apply clip mask.
3804 */
3805 if (image->debug != MagickFalse)
3806 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3807 if (image->mask == (Image *) NULL)
3808 return(MagickFalse);
cristy77ff0282010-09-13 00:51:10 +00003809 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00003810 if (cache_info == (Cache) NULL)
3811 return(MagickFalse);
3812 image_nexus=AcquirePixelCacheNexus(1);
3813 clip_nexus=AcquirePixelCacheNexus(1);
3814 if ((image_nexus == (NexusInfo **) NULL) ||
3815 (clip_nexus == (NexusInfo **) NULL))
3816 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
cristy09449f72010-01-23 03:08:36 +00003817 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3818 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3819 image_nexus[0],exception);
cristy3ed852e2009-09-05 21:47:34 +00003820 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3821 q=nexus_info->pixels;
3822 nexus_indexes=nexus_info->indexes;
3823 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3824 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3825 nexus_info->region.height,clip_nexus[0],&image->exception);
3826 GetMagickPixelPacket(image,&alpha);
3827 GetMagickPixelPacket(image,&beta);
3828 number_pixels=(MagickSizeType) nexus_info->region.width*
3829 nexus_info->region.height;
cristybb503372010-05-27 20:51:26 +00003830 for (i=0; i < (ssize_t) number_pixels; i++)
cristy3ed852e2009-09-05 21:47:34 +00003831 {
3832 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3833 break;
3834 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3835 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3836 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3837 &alpha,alpha.opacity,&beta);
cristyce70c172010-01-07 17:15:30 +00003838 q->red=ClampToQuantum(beta.red);
3839 q->green=ClampToQuantum(beta.green);
3840 q->blue=ClampToQuantum(beta.blue);
3841 q->opacity=ClampToQuantum(beta.opacity);
cristy3ed852e2009-09-05 21:47:34 +00003842 if (cache_info->active_index_channel != MagickFalse)
3843 nexus_indexes[i]=indexes[i];
3844 p++;
3845 q++;
3846 r++;
3847 }
3848 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3849 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
cristybb503372010-05-27 20:51:26 +00003850 if (i < (ssize_t) number_pixels)
cristy3ed852e2009-09-05 21:47:34 +00003851 return(MagickFalse);
3852 return(MagickTrue);
3853}
3854
3855/*
3856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3857% %
3858% %
3859% %
3860+ O p e n P i x e l C a c h e %
3861% %
3862% %
3863% %
3864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3865%
3866% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3867% dimensions, allocating space for the image pixels and optionally the
3868% colormap indexes, and memory mapping the cache if it is disk based. The
3869% cache nexus array is initialized as well.
3870%
3871% The format of the OpenPixelCache() method is:
3872%
3873% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3874% ExceptionInfo *exception)
3875%
3876% A description of each parameter follows:
3877%
3878% o image: the image.
3879%
3880% o mode: ReadMode, WriteMode, or IOMode.
3881%
3882% o exception: return any errors or warnings in this structure.
3883%
3884*/
3885
cristyd43a46b2010-01-21 02:13:41 +00003886static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
cristy3ed852e2009-09-05 21:47:34 +00003887{
3888 cache_info->mapped=MagickFalse;
3889 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3890 cache_info->length);
3891 if (cache_info->pixels == (PixelPacket *) NULL)
3892 {
3893 cache_info->mapped=MagickTrue;
3894 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3895 cache_info->length);
3896 }
3897}
3898
3899static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3900{
3901 CacheInfo
3902 *cache_info;
3903
3904 MagickOffsetType
3905 count,
3906 extent,
3907 offset;
3908
3909 cache_info=(CacheInfo *) image->cache;
3910 if (image->debug != MagickFalse)
3911 {
3912 char
3913 format[MaxTextExtent],
3914 message[MaxTextExtent];
3915
cristyb9080c92009-12-01 20:13:26 +00003916 (void) FormatMagickSize(length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00003917 (void) FormatMagickString(message,MaxTextExtent,
cristy2ce15c92010-03-12 14:03:41 +00003918 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00003919 cache_info->cache_filename,cache_info->file,format);
3920 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3921 }
3922 if (length != (MagickSizeType) ((MagickOffsetType) length))
3923 return(MagickFalse);
3924 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3925 if (extent < 0)
3926 return(MagickFalse);
3927 if ((MagickSizeType) extent >= length)
3928 return(MagickTrue);
3929 offset=(MagickOffsetType) length-1;
3930 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3931 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3932}
3933
3934static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3935 ExceptionInfo *exception)
3936{
3937 char
3938 format[MaxTextExtent],
3939 message[MaxTextExtent];
3940
3941 CacheInfo
3942 *cache_info,
3943 source_info;
3944
3945 MagickSizeType
3946 length,
3947 number_pixels;
3948
3949 MagickStatusType
3950 status;
3951
3952 size_t
cristye076a6e2010-08-15 19:59:43 +00003953 columns,
cristy3ed852e2009-09-05 21:47:34 +00003954 packet_size;
3955
cristy3ed852e2009-09-05 21:47:34 +00003956 if (image->debug != MagickFalse)
3957 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3958 if ((image->columns == 0) || (image->rows == 0))
3959 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3960 cache_info=(CacheInfo *) image->cache;
3961 source_info=(*cache_info);
3962 source_info.file=(-1);
cristye8c25f92010-06-03 00:53:06 +00003963 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3964 image->filename,(double) GetImageIndexInList(image));
cristy87528ea2009-09-10 14:53:56 +00003965 cache_info->mode=mode;
cristy3ed852e2009-09-05 21:47:34 +00003966 cache_info->rows=image->rows;
3967 cache_info->columns=image->columns;
3968 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3969 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
cristy73724512010-04-12 14:43:14 +00003970 if (image->ping != MagickFalse)
3971 {
3972 cache_info->storage_class=image->storage_class;
3973 cache_info->colorspace=image->colorspace;
3974 cache_info->type=PingCache;
3975 cache_info->pixels=(PixelPacket *) NULL;
3976 cache_info->indexes=(IndexPacket *) NULL;
3977 cache_info->length=0;
3978 return(MagickTrue);
3979 }
cristy3ed852e2009-09-05 21:47:34 +00003980 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3981 packet_size=sizeof(PixelPacket);
3982 if (cache_info->active_index_channel != MagickFalse)
3983 packet_size+=sizeof(IndexPacket);
3984 length=number_pixels*packet_size;
cristybb503372010-05-27 20:51:26 +00003985 columns=(size_t) (length/cache_info->rows/packet_size);
cristy3ed852e2009-09-05 21:47:34 +00003986 if (cache_info->columns != columns)
3987 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3988 image->filename);
3989 cache_info->length=length;
3990 status=AcquireMagickResource(AreaResource,cache_info->length);
3991 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3992 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3993 {
3994 status=AcquireMagickResource(MemoryResource,cache_info->length);
3995 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3996 (cache_info->type == MemoryCache))
3997 {
cristyd43a46b2010-01-21 02:13:41 +00003998 AllocatePixelCachePixels(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00003999 if (cache_info->pixels == (PixelPacket *) NULL)
4000 cache_info->pixels=source_info.pixels;
4001 else
4002 {
4003 /*
4004 Create memory pixel cache.
4005 */
4006 if (image->debug != MagickFalse)
4007 {
cristy97e7a572009-12-05 15:07:53 +00004008 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004009 format);
cristy3ed852e2009-09-05 21:47:34 +00004010 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004011 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
cristy3ed852e2009-09-05 21:47:34 +00004012 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
cristye8c25f92010-06-03 00:53:06 +00004013 (double) cache_info->columns,(double) cache_info->rows,
4014 format);
cristy3ed852e2009-09-05 21:47:34 +00004015 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4016 message);
4017 }
4018 cache_info->storage_class=image->storage_class;
4019 cache_info->colorspace=image->colorspace;
4020 cache_info->type=MemoryCache;
4021 cache_info->indexes=(IndexPacket *) NULL;
4022 if (cache_info->active_index_channel != MagickFalse)
4023 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4024 number_pixels);
4025 if (source_info.storage_class != UndefinedClass)
4026 {
4027 status|=ClonePixelCachePixels(cache_info,&source_info,
4028 exception);
4029 RelinquishPixelCachePixels(&source_info);
4030 }
4031 return(MagickTrue);
4032 }
4033 }
4034 RelinquishMagickResource(MemoryResource,cache_info->length);
4035 }
4036 /*
4037 Create pixel cache on disk.
4038 */
4039 status=AcquireMagickResource(DiskResource,cache_info->length);
4040 if (status == MagickFalse)
4041 {
4042 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4043 "CacheResourcesExhausted","`%s'",image->filename);
4044 return(MagickFalse);
4045 }
4046 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4047 {
4048 RelinquishMagickResource(DiskResource,cache_info->length);
4049 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4050 image->filename);
4051 return(MagickFalse);
4052 }
4053 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4054 cache_info->length);
4055 if (status == MagickFalse)
4056 {
4057 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4058 image->filename);
4059 return(MagickFalse);
4060 }
4061 cache_info->storage_class=image->storage_class;
4062 cache_info->colorspace=image->colorspace;
4063 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4064 status=AcquireMagickResource(AreaResource,cache_info->length);
4065 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4066 cache_info->type=DiskCache;
4067 else
4068 {
4069 status=AcquireMagickResource(MapResource,cache_info->length);
4070 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4071 (cache_info->type != MemoryCache))
4072 cache_info->type=DiskCache;
4073 else
4074 {
4075 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4076 cache_info->offset,(size_t) cache_info->length);
4077 if (cache_info->pixels == (PixelPacket *) NULL)
4078 {
4079 cache_info->pixels=source_info.pixels;
4080 cache_info->type=DiskCache;
4081 }
4082 else
4083 {
4084 /*
4085 Create file-backed memory-mapped pixel cache.
4086 */
4087 (void) ClosePixelCacheOnDisk(cache_info);
4088 cache_info->type=MapCache;
4089 cache_info->mapped=MagickTrue;
4090 cache_info->indexes=(IndexPacket *) NULL;
4091 if (cache_info->active_index_channel != MagickFalse)
4092 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4093 number_pixels);
4094 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4095 {
4096 status=ClonePixelCachePixels(cache_info,&source_info,
4097 exception);
4098 RelinquishPixelCachePixels(&source_info);
4099 }
4100 if (image->debug != MagickFalse)
4101 {
cristy97e7a572009-12-05 15:07:53 +00004102 (void) FormatMagickSize(cache_info->length,MagickTrue,
cristyb9080c92009-12-01 20:13:26 +00004103 format);
cristy3ed852e2009-09-05 21:47:34 +00004104 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004105 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
cristy3ed852e2009-09-05 21:47:34 +00004106 cache_info->filename,cache_info->cache_filename,
cristye8c25f92010-06-03 00:53:06 +00004107 cache_info->file,(double) cache_info->columns,(double)
4108 cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004109 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4110 message);
4111 }
4112 return(MagickTrue);
4113 }
4114 }
4115 RelinquishMagickResource(MapResource,cache_info->length);
4116 }
4117 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4118 {
4119 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4120 RelinquishPixelCachePixels(&source_info);
4121 }
4122 if (image->debug != MagickFalse)
4123 {
cristyb9080c92009-12-01 20:13:26 +00004124 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
cristy3ed852e2009-09-05 21:47:34 +00004125 (void) FormatMagickString(message,MaxTextExtent,
cristye8c25f92010-06-03 00:53:06 +00004126 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4127 cache_info->cache_filename,cache_info->file,(double)
4128 cache_info->columns,(double) cache_info->rows,format);
cristy3ed852e2009-09-05 21:47:34 +00004129 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4130 }
4131 return(MagickTrue);
4132}
4133
4134/*
4135%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4136% %
4137% %
4138% %
4139+ P e r s i s t P i x e l C a c h e %
4140% %
4141% %
4142% %
4143%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4144%
4145% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4146% persistent pixel cache is one that resides on disk and is not destroyed
4147% when the program exits.
4148%
4149% The format of the PersistPixelCache() method is:
4150%
4151% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4152% const MagickBooleanType attach,MagickOffsetType *offset,
4153% ExceptionInfo *exception)
4154%
4155% A description of each parameter follows:
4156%
4157% o image: the image.
4158%
4159% o filename: the persistent pixel cache filename.
4160%
cristy01b7eb02009-09-10 23:10:14 +00004161% o attach: A value other than zero initializes the persistent pixel
4162% cache.
4163%
cristy3ed852e2009-09-05 21:47:34 +00004164% o initialize: A value other than zero initializes the persistent pixel
4165% cache.
4166%
4167% o offset: the offset in the persistent cache to store pixels.
4168%
4169% o exception: return any errors or warnings in this structure.
4170%
4171*/
4172MagickExport MagickBooleanType PersistPixelCache(Image *image,
4173 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4174 ExceptionInfo *exception)
4175{
4176 CacheInfo
4177 *cache_info,
4178 *clone_info;
4179
4180 Image
4181 clone_image;
4182
cristy3ed852e2009-09-05 21:47:34 +00004183 MagickBooleanType
4184 status;
4185
cristye076a6e2010-08-15 19:59:43 +00004186 ssize_t
4187 page_size;
4188
cristy3ed852e2009-09-05 21:47:34 +00004189 assert(image != (Image *) NULL);
4190 assert(image->signature == MagickSignature);
4191 if (image->debug != MagickFalse)
4192 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4193 assert(image->cache != (void *) NULL);
4194 assert(filename != (const char *) NULL);
4195 assert(offset != (MagickOffsetType *) NULL);
cristy688f07b2009-09-27 15:19:13 +00004196 page_size=GetMagickPageSize();
cristy3ed852e2009-09-05 21:47:34 +00004197 cache_info=(CacheInfo *) image->cache;
4198 assert(cache_info->signature == MagickSignature);
4199 if (attach != MagickFalse)
4200 {
4201 /*
cristy01b7eb02009-09-10 23:10:14 +00004202 Attach existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004203 */
4204 if (image->debug != MagickFalse)
4205 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4206 "attach persistent cache");
4207 (void) CopyMagickString(cache_info->cache_filename,filename,
4208 MaxTextExtent);
4209 cache_info->type=DiskCache;
4210 cache_info->offset=(*offset);
4211 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4212 return(MagickFalse);
cristy688f07b2009-09-27 15:19:13 +00004213 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004214 return(MagickTrue);
4215 }
cristy01b7eb02009-09-10 23:10:14 +00004216 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4217 (cache_info->reference_count == 1))
cristy3ed852e2009-09-05 21:47:34 +00004218 {
cristyf84a1932010-01-03 18:00:18 +00004219 LockSemaphoreInfo(cache_info->semaphore);
cristy09449f72010-01-23 03:08:36 +00004220 if ((cache_info->mode != ReadMode) &&
4221 (cache_info->type != MemoryCache) &&
cristy3ed852e2009-09-05 21:47:34 +00004222 (cache_info->reference_count == 1))
4223 {
4224 int
4225 status;
4226
4227 /*
cristy01b7eb02009-09-10 23:10:14 +00004228 Usurp existing persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004229 */
4230 status=rename(cache_info->cache_filename,filename);
4231 if (status == 0)
4232 {
4233 (void) CopyMagickString(cache_info->cache_filename,filename,
4234 MaxTextExtent);
cristy688f07b2009-09-27 15:19:13 +00004235 *offset+=cache_info->length+page_size-(cache_info->length %
4236 page_size);
cristyf84a1932010-01-03 18:00:18 +00004237 UnlockSemaphoreInfo(cache_info->semaphore);
cristy87528ea2009-09-10 14:53:56 +00004238 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
cristy3ed852e2009-09-05 21:47:34 +00004239 if (image->debug != MagickFalse)
4240 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4241 "Usurp resident persistent cache");
cristy3ed852e2009-09-05 21:47:34 +00004242 return(MagickTrue);
4243 }
4244 }
cristyf84a1932010-01-03 18:00:18 +00004245 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004246 }
4247 /*
cristy01b7eb02009-09-10 23:10:14 +00004248 Clone persistent pixel cache.
cristy3ed852e2009-09-05 21:47:34 +00004249 */
4250 clone_image=(*image);
4251 clone_info=(CacheInfo *) clone_image.cache;
4252 image->cache=ClonePixelCache(cache_info);
4253 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4254 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4255 cache_info->type=DiskCache;
4256 cache_info->offset=(*offset);
4257 cache_info=(CacheInfo *) image->cache;
cristyabd6e372010-09-15 19:11:26 +00004258 status=OpenPixelCache(image,IOMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00004259 if (status != MagickFalse)
cristyabd6e372010-09-15 19:11:26 +00004260 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
cristy688f07b2009-09-27 15:19:13 +00004261 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
cristy3ed852e2009-09-05 21:47:34 +00004262 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4263 return(status);
4264}
4265
4266/*
4267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4268% %
4269% %
4270% %
4271+ Q u e u e A u t h e n t i c N e x u s %
4272% %
4273% %
4274% %
4275%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4276%
4277% QueueAuthenticNexus() allocates an region to store image pixels as defined
4278% by the region rectangle and returns a pointer to the region. This region is
4279% subsequently transferred from the pixel cache with
4280% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4281% pixels are transferred, otherwise a NULL is returned.
4282%
4283% The format of the QueueAuthenticNexus() method is:
4284%
cristy5f959472010-05-27 22:19:46 +00004285% PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4286% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004287% NexusInfo *nexus_info,ExceptionInfo *exception)
4288%
4289% A description of each parameter follows:
4290%
4291% o image: the image.
4292%
4293% o x,y,columns,rows: These values define the perimeter of a region of
4294% pixels.
4295%
4296% o nexus_info: the cache nexus to set.
4297%
4298% o exception: return any errors or warnings in this structure.
4299%
4300*/
cristybb503372010-05-27 20:51:26 +00004301MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
cristy30097232010-07-01 02:16:30 +00004302 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4303 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00004304{
4305 CacheInfo
4306 *cache_info;
4307
4308 MagickOffsetType
4309 offset;
4310
4311 MagickSizeType
4312 number_pixels;
4313
4314 RectangleInfo
4315 region;
4316
4317 /*
4318 Validate pixel cache geometry.
4319 */
cristy77ff0282010-09-13 00:51:10 +00004320 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4321 if (cache_info == (Cache) NULL)
4322 return((PixelPacket *) NULL);
cristy3ed852e2009-09-05 21:47:34 +00004323 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4324 {
4325 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4326 "NoPixelsDefinedInCache","`%s'",image->filename);
4327 return((PixelPacket *) NULL);
4328 }
cristybb503372010-05-27 20:51:26 +00004329 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4330 (y >= (ssize_t) cache_info->rows))
cristy3ed852e2009-09-05 21:47:34 +00004331 {
4332 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4333 "PixelsAreNotAuthentic","`%s'",image->filename);
4334 return((PixelPacket *) NULL);
4335 }
4336 offset=(MagickOffsetType) y*cache_info->columns+x;
4337 if (offset < 0)
4338 return((PixelPacket *) NULL);
4339 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4340 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4341 if ((MagickSizeType) offset >= number_pixels)
4342 return((PixelPacket *) NULL);
4343 /*
4344 Return pixel cache.
4345 */
4346 region.x=x;
4347 region.y=y;
4348 region.width=columns;
4349 region.height=rows;
4350 return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4351}
4352
4353/*
4354%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4355% %
4356% %
4357% %
4358+ Q u e u e A u t h e n t i c P i x e l s C a c h e %
4359% %
4360% %
4361% %
4362%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4363%
4364% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4365% defined by the region rectangle and returns a pointer to the region. This
4366% region is subsequently transferred from the pixel cache with
4367% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4368% pixels are transferred, otherwise a NULL is returned.
4369%
4370% The format of the QueueAuthenticPixelsCache() method is:
4371%
cristybb503372010-05-27 20:51:26 +00004372% PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4373% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004374% ExceptionInfo *exception)
4375%
4376% A description of each parameter follows:
4377%
4378% o image: the image.
4379%
4380% o x,y,columns,rows: These values define the perimeter of a region of
4381% pixels.
4382%
4383% o exception: return any errors or warnings in this structure.
4384%
4385*/
cristybb503372010-05-27 20:51:26 +00004386static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4387 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004388 ExceptionInfo *exception)
4389{
4390 CacheInfo
4391 *cache_info;
4392
cristy6ebe97c2010-07-03 01:17:28 +00004393 int
cristy3ed852e2009-09-05 21:47:34 +00004394 id;
4395
4396 PixelPacket
4397 *pixels;
4398
cristy77ff0282010-09-13 00:51:10 +00004399 cache_info=(CacheInfo *) image->cache;
cristy3ed852e2009-09-05 21:47:34 +00004400 if (cache_info == (Cache) NULL)
4401 return((PixelPacket *) NULL);
4402 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00004403 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00004404 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4405 exception);
4406 return(pixels);
4407}
4408
4409/*
4410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4411% %
4412% %
4413% %
4414% Q u e u e A u t h e n t i c P i x e l s %
4415% %
4416% %
4417% %
4418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4419%
4420% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4421% successfully intialized a pointer to a PixelPacket array representing the
4422% region is returned, otherwise NULL is returned. The returned pointer may
4423% point to a temporary working buffer for the pixels or it may point to the
4424% final location of the pixels in memory.
4425%
4426% Write-only access means that any existing pixel values corresponding to
4427% the region are ignored. This is useful if the initial image is being
4428% created from scratch, or if the existing pixel values are to be
4429% completely replaced without need to refer to their pre-existing values.
4430% The application is free to read and write the pixel buffer returned by
4431% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4432% initialize the pixel array values. Initializing pixel array values is the
4433% application's responsibility.
4434%
4435% Performance is maximized if the selected region is part of one row, or
4436% one or more full rows, since then there is opportunity to access the
cristyad4e5b22010-01-10 00:04:19 +00004437% pixels in-place (without a copy) if the image is in memory, or in a
4438% memory-mapped file. The returned pointer must *never* be deallocated
cristy3ed852e2009-09-05 21:47:34 +00004439% by the user.
4440%
4441% Pixels accessed via the returned pointer represent a simple array of type
4442% PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4443% call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4444% the black color component or the colormap indexes (of type IndexPacket)
4445% corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4446% array has been updated, the changes must be saved back to the underlying
4447% image using SyncAuthenticPixels() or they may be lost.
4448%
4449% The format of the QueueAuthenticPixels() method is:
4450%
cristy5f959472010-05-27 22:19:46 +00004451% PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4452% const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004453% ExceptionInfo *exception)
4454%
4455% A description of each parameter follows:
4456%
4457% o image: the image.
4458%
4459% o x,y,columns,rows: These values define the perimeter of a region of
4460% pixels.
4461%
4462% o exception: return any errors or warnings in this structure.
4463%
4464*/
cristybb503372010-05-27 20:51:26 +00004465MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4466 const ssize_t y,const size_t columns,const size_t rows,
cristy3ed852e2009-09-05 21:47:34 +00004467 ExceptionInfo *exception)
4468{
4469 CacheInfo
4470 *cache_info;
4471
4472 PixelPacket
4473 *pixels;
4474
4475 assert(image != (Image *) NULL);
4476 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00004477 assert(image->cache != (Cache) NULL);
4478 cache_info=(CacheInfo *) image->cache;
4479 assert(cache_info->signature == MagickSignature);
4480 if (cache_info->methods.queue_authentic_pixels_handler ==
4481 (QueueAuthenticPixelsHandler) NULL)
4482 return((PixelPacket *) NULL);
4483 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4484 rows,exception);
4485 return(pixels);
4486}
4487
4488/*
4489%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4490% %
4491% %
4492% %
4493+ R e a d P i x e l C a c h e I n d e x e s %
4494% %
4495% %
4496% %
4497%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4498%
4499% ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4500% the pixel cache.
4501%
4502% The format of the ReadPixelCacheIndexes() method is:
4503%
4504% MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4505% NexusInfo *nexus_info,ExceptionInfo *exception)
4506%
4507% A description of each parameter follows:
4508%
4509% o cache_info: the pixel cache.
4510%
4511% o nexus_info: the cache nexus to read the colormap indexes.
4512%
4513% o exception: return any errors or warnings in this structure.
4514%
4515*/
4516static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4517 NexusInfo *nexus_info,ExceptionInfo *exception)
4518{
4519 MagickOffsetType
4520 count,
4521 offset;
4522
4523 MagickSizeType
4524 length,
4525 number_pixels;
4526
4527 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004528 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004529
cristybb503372010-05-27 20:51:26 +00004530 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00004531 y;
4532
cristybb503372010-05-27 20:51:26 +00004533 size_t
cristy3ed852e2009-09-05 21:47:34 +00004534 rows;
4535
cristy3ed852e2009-09-05 21:47:34 +00004536 if (cache_info->active_index_channel == MagickFalse)
4537 return(MagickFalse);
4538 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4539 return(MagickTrue);
4540 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4541 nexus_info->region.x;
4542 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4543 rows=nexus_info->region.height;
4544 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004545 q=nexus_info->indexes;
4546 switch (cache_info->type)
4547 {
4548 case MemoryCache:
4549 case MapCache:
4550 {
4551 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00004552 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004553
4554 /*
4555 Read indexes from memory.
4556 */
cristydd341db2010-03-04 19:06:38 +00004557 if ((cache_info->columns == nexus_info->region.width) &&
4558 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4559 {
4560 length=number_pixels;
4561 rows=1UL;
4562 }
cristy3ed852e2009-09-05 21:47:34 +00004563 p=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00004564 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004565 {
4566 (void) CopyMagickMemory(q,p,(size_t) length);
4567 p+=cache_info->columns;
4568 q+=nexus_info->region.width;
4569 }
4570 break;
4571 }
4572 case DiskCache:
4573 {
4574 /*
4575 Read indexes from disk.
4576 */
4577 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4578 {
4579 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4580 cache_info->cache_filename);
4581 return(MagickFalse);
4582 }
cristydd341db2010-03-04 19:06:38 +00004583 if ((cache_info->columns == nexus_info->region.width) &&
4584 (number_pixels < MagickMaxBufferExtent))
4585 {
4586 length=number_pixels;
4587 rows=1UL;
4588 }
cristy3ed852e2009-09-05 21:47:34 +00004589 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00004590 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004591 {
4592 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4593 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4594 if ((MagickSizeType) count < length)
4595 break;
4596 offset+=cache_info->columns;
4597 q+=nexus_info->region.width;
4598 }
cristybb503372010-05-27 20:51:26 +00004599 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004600 {
4601 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4602 cache_info->cache_filename);
4603 return(MagickFalse);
4604 }
4605 break;
4606 }
4607 default:
4608 break;
4609 }
4610 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004611 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004612 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004613 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004614 nexus_info->region.width,(double) nexus_info->region.height,(double)
4615 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004616 return(MagickTrue);
4617}
4618
4619/*
4620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4621% %
4622% %
4623% %
4624+ R e a d P i x e l C a c h e P i x e l s %
4625% %
4626% %
4627% %
4628%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4629%
4630% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4631% cache.
4632%
4633% The format of the ReadPixelCachePixels() method is:
4634%
4635% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4636% NexusInfo *nexus_info,ExceptionInfo *exception)
4637%
4638% A description of each parameter follows:
4639%
4640% o cache_info: the pixel cache.
4641%
4642% o nexus_info: the cache nexus to read the pixels.
4643%
4644% o exception: return any errors or warnings in this structure.
4645%
4646*/
4647static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4648 NexusInfo *nexus_info,ExceptionInfo *exception)
4649{
4650 MagickOffsetType
4651 count,
4652 offset;
4653
4654 MagickSizeType
4655 length,
4656 number_pixels;
4657
cristy3ed852e2009-09-05 21:47:34 +00004658 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004659 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00004660
cristye076a6e2010-08-15 19:59:43 +00004661 register ssize_t
4662 y;
4663
cristybb503372010-05-27 20:51:26 +00004664 size_t
cristy3ed852e2009-09-05 21:47:34 +00004665 rows;
4666
cristy3ed852e2009-09-05 21:47:34 +00004667 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4668 return(MagickTrue);
4669 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4670 nexus_info->region.x;
4671 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4672 rows=nexus_info->region.height;
4673 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00004674 q=nexus_info->pixels;
4675 switch (cache_info->type)
4676 {
4677 case MemoryCache:
4678 case MapCache:
4679 {
4680 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00004681 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00004682
4683 /*
4684 Read pixels from memory.
4685 */
cristydd341db2010-03-04 19:06:38 +00004686 if ((cache_info->columns == nexus_info->region.width) &&
4687 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4688 {
4689 length=number_pixels;
4690 rows=1UL;
4691 }
cristy3ed852e2009-09-05 21:47:34 +00004692 p=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00004693 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004694 {
4695 (void) CopyMagickMemory(q,p,(size_t) length);
4696 p+=cache_info->columns;
4697 q+=nexus_info->region.width;
4698 }
4699 break;
4700 }
4701 case DiskCache:
4702 {
4703 /*
4704 Read pixels from disk.
4705 */
4706 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4707 {
4708 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4709 cache_info->cache_filename);
4710 return(MagickFalse);
4711 }
cristydd341db2010-03-04 19:06:38 +00004712 if ((cache_info->columns == nexus_info->region.width) &&
4713 (number_pixels < MagickMaxBufferExtent))
4714 {
4715 length=number_pixels;
4716 rows=1UL;
4717 }
cristybb503372010-05-27 20:51:26 +00004718 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00004719 {
4720 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4721 sizeof(*q),length,(unsigned char *) q);
4722 if ((MagickSizeType) count < length)
4723 break;
4724 offset+=cache_info->columns;
4725 q+=nexus_info->region.width;
4726 }
cristybb503372010-05-27 20:51:26 +00004727 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00004728 {
4729 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4730 cache_info->cache_filename);
4731 return(MagickFalse);
4732 }
4733 break;
4734 }
4735 default:
4736 break;
4737 }
4738 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00004739 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00004740 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00004741 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00004742 nexus_info->region.width,(double) nexus_info->region.height,(double)
4743 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00004744 return(MagickTrue);
4745}
4746
4747/*
4748%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4749% %
4750% %
4751% %
4752+ R e f e r e n c e P i x e l C a c h e %
4753% %
4754% %
4755% %
4756%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4757%
4758% ReferencePixelCache() increments the reference count associated with the
4759% pixel cache returning a pointer to the cache.
4760%
4761% The format of the ReferencePixelCache method is:
4762%
4763% Cache ReferencePixelCache(Cache cache_info)
4764%
4765% A description of each parameter follows:
4766%
4767% o cache_info: the pixel cache.
4768%
4769*/
4770MagickExport Cache ReferencePixelCache(Cache cache)
4771{
4772 CacheInfo
4773 *cache_info;
4774
4775 assert(cache != (Cache *) NULL);
4776 cache_info=(CacheInfo *) cache;
4777 assert(cache_info->signature == MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00004778 LockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004779 cache_info->reference_count++;
cristyf84a1932010-01-03 18:00:18 +00004780 UnlockSemaphoreInfo(cache_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00004781 return(cache_info);
4782}
4783
4784/*
4785%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4786% %
4787% %
4788% %
4789+ S e t P i x e l C a c h e M e t h o d s %
4790% %
4791% %
4792% %
4793%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4794%
4795% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4796%
4797% The format of the SetPixelCacheMethods() method is:
4798%
4799% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4800%
4801% A description of each parameter follows:
4802%
4803% o cache: the pixel cache.
4804%
4805% o cache_methods: Specifies a pointer to a CacheMethods structure.
4806%
4807*/
4808MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4809{
4810 CacheInfo
4811 *cache_info;
4812
4813 GetOneAuthenticPixelFromHandler
4814 get_one_authentic_pixel_from_handler;
4815
4816 GetOneVirtualPixelFromHandler
4817 get_one_virtual_pixel_from_handler;
4818
4819 /*
4820 Set cache pixel methods.
4821 */
4822 assert(cache != (Cache) NULL);
4823 assert(cache_methods != (CacheMethods *) NULL);
4824 cache_info=(CacheInfo *) cache;
4825 assert(cache_info->signature == MagickSignature);
4826 if (cache_info->debug != MagickFalse)
4827 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4828 cache_info->filename);
4829 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4830 cache_info->methods.get_virtual_pixel_handler=
4831 cache_methods->get_virtual_pixel_handler;
4832 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4833 cache_info->methods.destroy_pixel_handler=
4834 cache_methods->destroy_pixel_handler;
4835 if (cache_methods->get_virtual_indexes_from_handler !=
4836 (GetVirtualIndexesFromHandler) NULL)
4837 cache_info->methods.get_virtual_indexes_from_handler=
4838 cache_methods->get_virtual_indexes_from_handler;
4839 if (cache_methods->get_authentic_pixels_handler !=
4840 (GetAuthenticPixelsHandler) NULL)
4841 cache_info->methods.get_authentic_pixels_handler=
4842 cache_methods->get_authentic_pixels_handler;
4843 if (cache_methods->queue_authentic_pixels_handler !=
4844 (QueueAuthenticPixelsHandler) NULL)
4845 cache_info->methods.queue_authentic_pixels_handler=
4846 cache_methods->queue_authentic_pixels_handler;
4847 if (cache_methods->sync_authentic_pixels_handler !=
4848 (SyncAuthenticPixelsHandler) NULL)
4849 cache_info->methods.sync_authentic_pixels_handler=
4850 cache_methods->sync_authentic_pixels_handler;
4851 if (cache_methods->get_authentic_pixels_from_handler !=
4852 (GetAuthenticPixelsFromHandler) NULL)
4853 cache_info->methods.get_authentic_pixels_from_handler=
4854 cache_methods->get_authentic_pixels_from_handler;
4855 if (cache_methods->get_authentic_indexes_from_handler !=
4856 (GetAuthenticIndexesFromHandler) NULL)
4857 cache_info->methods.get_authentic_indexes_from_handler=
4858 cache_methods->get_authentic_indexes_from_handler;
4859 get_one_virtual_pixel_from_handler=
4860 cache_info->methods.get_one_virtual_pixel_from_handler;
4861 if (get_one_virtual_pixel_from_handler !=
4862 (GetOneVirtualPixelFromHandler) NULL)
4863 cache_info->methods.get_one_virtual_pixel_from_handler=
4864 cache_methods->get_one_virtual_pixel_from_handler;
4865 get_one_authentic_pixel_from_handler=
4866 cache_methods->get_one_authentic_pixel_from_handler;
4867 if (get_one_authentic_pixel_from_handler !=
4868 (GetOneAuthenticPixelFromHandler) NULL)
4869 cache_info->methods.get_one_authentic_pixel_from_handler=
4870 cache_methods->get_one_authentic_pixel_from_handler;
4871}
4872
4873/*
4874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4875% %
4876% %
4877% %
4878+ S e t P i x e l C a c h e N e x u s P i x e l s %
4879% %
4880% %
4881% %
4882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4883%
4884% SetPixelCacheNexusPixels() defines the region of the cache for the
4885% specified cache nexus.
4886%
4887% The format of the SetPixelCacheNexusPixels() method is:
4888%
4889% PixelPacket SetPixelCacheNexusPixels(const Image *image,
4890% const RectangleInfo *region,NexusInfo *nexus_info,
4891% ExceptionInfo *exception)
4892%
4893% A description of each parameter follows:
4894%
4895% o image: the image.
4896%
4897% o region: A pointer to the RectangleInfo structure that defines the
4898% region of this particular cache nexus.
4899%
4900% o nexus_info: the cache nexus to set.
4901%
4902% o exception: return any errors or warnings in this structure.
4903%
4904*/
cristyabd6e372010-09-15 19:11:26 +00004905
4906static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4907 NexusInfo *nexus_info,ExceptionInfo *exception)
4908{
4909 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4910 return(MagickFalse);
4911 nexus_info->mapped=MagickFalse;
4912 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4913 nexus_info->length);
4914 if (nexus_info->cache == (PixelPacket *) NULL)
4915 {
4916 nexus_info->mapped=MagickTrue;
4917 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4918 nexus_info->length);
4919 }
4920 if (nexus_info->cache == (PixelPacket *) NULL)
4921 {
4922 (void) ThrowMagickException(exception,GetMagickModule(),
4923 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4924 cache_info->filename);
4925 return(MagickFalse);
4926 }
4927 return(MagickTrue);
4928}
4929
cristy3ed852e2009-09-05 21:47:34 +00004930static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4931 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4932{
4933 CacheInfo
4934 *cache_info;
4935
4936 MagickBooleanType
4937 status;
4938
cristy3ed852e2009-09-05 21:47:34 +00004939 MagickSizeType
4940 length,
4941 number_pixels;
4942
cristy3ed852e2009-09-05 21:47:34 +00004943 cache_info=(CacheInfo *) image->cache;
4944 assert(cache_info->signature == MagickSignature);
4945 if (cache_info->type == UndefinedCache)
4946 return((PixelPacket *) NULL);
cristydc8b63f2010-03-13 16:11:14 +00004947 nexus_info->region=(*region);
cristy73724512010-04-12 14:43:14 +00004948 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4949 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
cristy3ed852e2009-09-05 21:47:34 +00004950 {
cristybb503372010-05-27 20:51:26 +00004951 ssize_t
cristybad067a2010-02-15 17:20:55 +00004952 x,
4953 y;
cristy3ed852e2009-09-05 21:47:34 +00004954
cristyeaedf062010-05-29 22:36:02 +00004955 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4956 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
cristybb503372010-05-27 20:51:26 +00004957 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4958 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
cristyed733b32010-09-17 16:27:34 +00004959 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
cristy731c3532010-02-15 15:40:03 +00004960 ((nexus_info->region.width == cache_info->columns) ||
4961 ((nexus_info->region.width % cache_info->columns) == 0)))))
4962 {
4963 MagickOffsetType
4964 offset;
4965
4966 /*
4967 Pixels are accessed directly from memory.
4968 */
4969 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4970 nexus_info->region.x;
4971 nexus_info->pixels=cache_info->pixels+offset;
4972 nexus_info->indexes=(IndexPacket *) NULL;
4973 if (cache_info->active_index_channel != MagickFalse)
4974 nexus_info->indexes=cache_info->indexes+offset;
4975 return(nexus_info->pixels);
cristy3ed852e2009-09-05 21:47:34 +00004976 }
4977 }
4978 /*
4979 Pixels are stored in a cache region until they are synced to the cache.
4980 */
4981 number_pixels=(MagickSizeType) nexus_info->region.width*
4982 nexus_info->region.height;
4983 length=number_pixels*sizeof(PixelPacket);
4984 if (cache_info->active_index_channel != MagickFalse)
4985 length+=number_pixels*sizeof(IndexPacket);
4986 if (nexus_info->cache == (PixelPacket *) NULL)
4987 {
4988 nexus_info->length=length;
4989 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4990 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00004991 {
4992 nexus_info->length=0;
4993 return((PixelPacket *) NULL);
4994 }
cristy3ed852e2009-09-05 21:47:34 +00004995 }
4996 else
4997 if (nexus_info->length != length)
4998 {
4999 RelinquishCacheNexusPixels(nexus_info);
5000 nexus_info->length=length;
5001 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5002 if (status == MagickFalse)
cristy5485e372010-09-15 19:02:29 +00005003 {
5004 nexus_info->length=0;
5005 return((PixelPacket *) NULL);
5006 }
cristy3ed852e2009-09-05 21:47:34 +00005007 }
5008 nexus_info->pixels=nexus_info->cache;
5009 nexus_info->indexes=(IndexPacket *) NULL;
5010 if (cache_info->active_index_channel != MagickFalse)
5011 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5012 return(nexus_info->pixels);
5013}
5014
5015/*
5016%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5017% %
5018% %
5019% %
5020% S e t P i x e l C a c h e V i r t u a l M e t h o d %
5021% %
5022% %
5023% %
5024%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5025%
5026% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5027% pixel cache and returns the previous setting. A virtual pixel is any pixel
5028% access that is outside the boundaries of the image cache.
5029%
5030% The format of the SetPixelCacheVirtualMethod() method is:
5031%
5032% VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5033% const VirtualPixelMethod virtual_pixel_method)
5034%
5035% A description of each parameter follows:
5036%
5037% o image: the image.
5038%
5039% o virtual_pixel_method: choose the type of virtual pixel.
5040%
5041*/
5042MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5043 const VirtualPixelMethod virtual_pixel_method)
5044{
5045 CacheInfo
5046 *cache_info;
5047
5048 VirtualPixelMethod
5049 method;
5050
5051 assert(image != (Image *) NULL);
5052 assert(image->signature == MagickSignature);
5053 if (image->debug != MagickFalse)
5054 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5055 assert(image->cache != (Cache) NULL);
5056 cache_info=(CacheInfo *) image->cache;
5057 assert(cache_info->signature == MagickSignature);
5058 method=cache_info->virtual_pixel_method;
5059 cache_info->virtual_pixel_method=virtual_pixel_method;
5060 return(method);
5061}
5062
5063/*
5064%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5065% %
5066% %
5067% %
5068+ S y n c A u t h e n t i c P i x e l C a c h e N e x u s %
5069% %
5070% %
5071% %
5072%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5073%
5074% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5075% in-memory or disk cache. The method returns MagickTrue if the pixel region
5076% is synced, otherwise MagickFalse.
5077%
5078% The format of the SyncAuthenticPixelCacheNexus() method is:
5079%
5080% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5081% NexusInfo *nexus_info,ExceptionInfo *exception)
5082%
5083% A description of each parameter follows:
5084%
5085% o image: the image.
5086%
5087% o nexus_info: the cache nexus to sync.
5088%
5089% o exception: return any errors or warnings in this structure.
5090%
5091*/
5092MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5093 NexusInfo *nexus_info,ExceptionInfo *exception)
5094{
5095 CacheInfo
5096 *cache_info;
5097
5098 MagickBooleanType
5099 status;
5100
5101 /*
5102 Transfer pixels to the cache.
5103 */
5104 assert(image != (Image *) NULL);
5105 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005106 if (image->cache == (Cache) NULL)
5107 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5108 cache_info=(CacheInfo *) image->cache;
5109 if (cache_info->type == UndefinedCache)
5110 return(MagickFalse);
5111 if ((image->clip_mask != (Image *) NULL) &&
5112 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5113 return(MagickFalse);
5114 if ((image->mask != (Image *) NULL) &&
5115 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5116 return(MagickFalse);
5117 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5118 return(MagickTrue);
5119 assert(cache_info->signature == MagickSignature);
5120 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5121 if ((cache_info->active_index_channel != MagickFalse) &&
5122 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5123 return(MagickFalse);
5124 return(status);
5125}
5126
5127/*
5128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5129% %
5130% %
5131% %
5132+ S y n c A u t h e n t i c P i x e l C a c h e %
5133% %
5134% %
5135% %
5136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5137%
5138% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5139% or disk cache. The method returns MagickTrue if the pixel region is synced,
5140% otherwise MagickFalse.
5141%
5142% The format of the SyncAuthenticPixelsCache() method is:
5143%
5144% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5145% ExceptionInfo *exception)
5146%
5147% A description of each parameter follows:
5148%
5149% o image: the image.
5150%
5151% o exception: return any errors or warnings in this structure.
5152%
5153*/
5154static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5155 ExceptionInfo *exception)
5156{
5157 CacheInfo
5158 *cache_info;
5159
cristy6ebe97c2010-07-03 01:17:28 +00005160 int
cristy3ed852e2009-09-05 21:47:34 +00005161 id;
5162
5163 MagickBooleanType
5164 status;
5165
5166 cache_info=(CacheInfo *) image->cache;
5167 id=GetOpenMPThreadId();
cristy6ebe97c2010-07-03 01:17:28 +00005168 assert(id < (int) cache_info->number_threads);
cristy3ed852e2009-09-05 21:47:34 +00005169 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5170 exception);
5171 return(status);
5172}
5173
5174/*
5175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5176% %
5177% %
5178% %
5179% S y n c A u t h e n t i c P i x e l s %
5180% %
5181% %
5182% %
5183%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5184%
5185% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5186% The method returns MagickTrue if the pixel region is flushed, otherwise
5187% MagickFalse.
5188%
5189% The format of the SyncAuthenticPixels() method is:
5190%
5191% MagickBooleanType SyncAuthenticPixels(Image *image,
5192% ExceptionInfo *exception)
5193%
5194% A description of each parameter follows:
5195%
5196% o image: the image.
5197%
5198% o exception: return any errors or warnings in this structure.
5199%
5200*/
5201MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5202 ExceptionInfo *exception)
5203{
5204 CacheInfo
5205 *cache_info;
5206
5207 assert(image != (Image *) NULL);
5208 assert(image->signature == MagickSignature);
cristy3ed852e2009-09-05 21:47:34 +00005209 assert(image->cache != (Cache) NULL);
5210 cache_info=(CacheInfo *) image->cache;
5211 assert(cache_info->signature == MagickSignature);
5212 if (cache_info->methods.sync_authentic_pixels_handler ==
5213 (SyncAuthenticPixelsHandler) NULL)
5214 return(MagickFalse);
5215 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5216}
5217
5218/*
5219%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5220% %
5221% %
5222% %
5223+ W r i t e P i x e l C a c h e I n d e x e s %
5224% %
5225% %
5226% %
5227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5228%
5229% WritePixelCacheIndexes() writes the colormap indexes to the specified
5230% region of the pixel cache.
5231%
5232% The format of the WritePixelCacheIndexes() method is:
5233%
5234% MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5235% NexusInfo *nexus_info,ExceptionInfo *exception)
5236%
5237% A description of each parameter follows:
5238%
5239% o cache_info: the pixel cache.
5240%
5241% o nexus_info: the cache nexus to write the colormap indexes.
5242%
5243% o exception: return any errors or warnings in this structure.
5244%
5245*/
5246static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5247 NexusInfo *nexus_info,ExceptionInfo *exception)
5248{
5249 MagickOffsetType
5250 count,
5251 offset;
5252
5253 MagickSizeType
5254 length,
5255 number_pixels;
5256
5257 register const IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005258 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005259
cristybb503372010-05-27 20:51:26 +00005260 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00005261 y;
5262
cristybb503372010-05-27 20:51:26 +00005263 size_t
cristy3ed852e2009-09-05 21:47:34 +00005264 rows;
5265
cristy3ed852e2009-09-05 21:47:34 +00005266 if (cache_info->active_index_channel == MagickFalse)
5267 return(MagickFalse);
5268 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5269 return(MagickTrue);
5270 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5271 nexus_info->region.x;
5272 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5273 rows=nexus_info->region.height;
5274 number_pixels=(MagickSizeType) length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005275 p=nexus_info->indexes;
5276 switch (cache_info->type)
5277 {
5278 case MemoryCache:
5279 case MapCache:
5280 {
5281 register IndexPacket
cristyc47d1f82009-11-26 01:44:43 +00005282 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005283
5284 /*
5285 Write indexes to memory.
5286 */
cristydd341db2010-03-04 19:06:38 +00005287 if ((cache_info->columns == nexus_info->region.width) &&
5288 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5289 {
5290 length=number_pixels;
5291 rows=1UL;
5292 }
cristy3ed852e2009-09-05 21:47:34 +00005293 q=cache_info->indexes+offset;
cristybb503372010-05-27 20:51:26 +00005294 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005295 {
5296 (void) CopyMagickMemory(q,p,(size_t) length);
5297 p+=nexus_info->region.width;
5298 q+=cache_info->columns;
5299 }
5300 break;
5301 }
5302 case DiskCache:
5303 {
5304 /*
5305 Write indexes to disk.
5306 */
5307 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5308 {
5309 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5310 cache_info->cache_filename);
5311 return(MagickFalse);
5312 }
cristydd341db2010-03-04 19:06:38 +00005313 if ((cache_info->columns == nexus_info->region.width) &&
5314 (number_pixels < MagickMaxBufferExtent))
5315 {
5316 length=number_pixels;
5317 rows=1UL;
5318 }
cristy3ed852e2009-09-05 21:47:34 +00005319 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
cristybb503372010-05-27 20:51:26 +00005320 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005321 {
5322 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5323 sizeof(PixelPacket)+offset*sizeof(*p),length,
5324 (const unsigned char *) p);
5325 if ((MagickSizeType) count < length)
5326 break;
5327 p+=nexus_info->region.width;
5328 offset+=cache_info->columns;
5329 }
cristybb503372010-05-27 20:51:26 +00005330 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005331 {
5332 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5333 cache_info->cache_filename);
5334 return(MagickFalse);
5335 }
5336 break;
5337 }
5338 default:
5339 break;
5340 }
5341 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005342 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005343 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005344 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005345 nexus_info->region.width,(double) nexus_info->region.height,(double)
5346 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005347 return(MagickTrue);
5348}
5349
5350/*
5351%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5352% %
5353% %
5354% %
5355+ W r i t e C a c h e P i x e l s %
5356% %
5357% %
5358% %
5359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5360%
5361% WritePixelCachePixels() writes image pixels to the specified region of the
5362% pixel cache.
5363%
5364% The format of the WritePixelCachePixels() method is:
5365%
5366% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5367% NexusInfo *nexus_info,ExceptionInfo *exception)
5368%
5369% A description of each parameter follows:
5370%
5371% o cache_info: the pixel cache.
5372%
5373% o nexus_info: the cache nexus to write the pixels.
5374%
5375% o exception: return any errors or warnings in this structure.
5376%
5377*/
5378static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5379 NexusInfo *nexus_info,ExceptionInfo *exception)
5380{
5381 MagickOffsetType
5382 count,
5383 offset;
5384
5385 MagickSizeType
5386 length,
5387 number_pixels;
5388
cristy3ed852e2009-09-05 21:47:34 +00005389 register const PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005390 *restrict p;
cristy3ed852e2009-09-05 21:47:34 +00005391
cristybb503372010-05-27 20:51:26 +00005392 register ssize_t
cristy25ffffb2009-12-07 17:15:07 +00005393 y;
5394
cristybb503372010-05-27 20:51:26 +00005395 size_t
cristy3ed852e2009-09-05 21:47:34 +00005396 rows;
5397
cristy3ed852e2009-09-05 21:47:34 +00005398 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5399 return(MagickTrue);
5400 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5401 nexus_info->region.x;
5402 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5403 rows=nexus_info->region.height;
5404 number_pixels=length*rows;
cristy3ed852e2009-09-05 21:47:34 +00005405 p=nexus_info->pixels;
5406 switch (cache_info->type)
5407 {
5408 case MemoryCache:
5409 case MapCache:
5410 {
5411 register PixelPacket
cristyc47d1f82009-11-26 01:44:43 +00005412 *restrict q;
cristy3ed852e2009-09-05 21:47:34 +00005413
5414 /*
5415 Write pixels to memory.
5416 */
cristydd341db2010-03-04 19:06:38 +00005417 if ((cache_info->columns == nexus_info->region.width) &&
5418 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5419 {
5420 length=number_pixels;
5421 rows=1UL;
5422 }
cristy3ed852e2009-09-05 21:47:34 +00005423 q=cache_info->pixels+offset;
cristybb503372010-05-27 20:51:26 +00005424 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005425 {
5426 (void) CopyMagickMemory(q,p,(size_t) length);
5427 p+=nexus_info->region.width;
5428 q+=cache_info->columns;
5429 }
5430 break;
5431 }
5432 case DiskCache:
5433 {
5434 /*
5435 Write pixels to disk.
5436 */
5437 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5438 {
5439 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5440 cache_info->cache_filename);
5441 return(MagickFalse);
5442 }
cristydd341db2010-03-04 19:06:38 +00005443 if ((cache_info->columns == nexus_info->region.width) &&
5444 (number_pixels < MagickMaxBufferExtent))
5445 {
5446 length=number_pixels;
5447 rows=1UL;
5448 }
cristybb503372010-05-27 20:51:26 +00005449 for (y=0; y < (ssize_t) rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00005450 {
5451 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5452 sizeof(*p),length,(const unsigned char *) p);
5453 if ((MagickSizeType) count < length)
5454 break;
5455 p+=nexus_info->region.width;
5456 offset+=cache_info->columns;
5457 }
cristybb503372010-05-27 20:51:26 +00005458 if (y < (ssize_t) rows)
cristy3ed852e2009-09-05 21:47:34 +00005459 {
5460 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5461 cache_info->cache_filename);
5462 return(MagickFalse);
5463 }
5464 break;
5465 }
5466 default:
5467 break;
5468 }
5469 if ((cache_info->debug != MagickFalse) &&
cristy30097232010-07-01 02:16:30 +00005470 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
cristye8c25f92010-06-03 00:53:06 +00005471 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
cristy6d8abba2010-06-03 01:10:47 +00005472 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
cristye8c25f92010-06-03 00:53:06 +00005473 nexus_info->region.width,(double) nexus_info->region.height,(double)
5474 nexus_info->region.x,(double) nexus_info->region.y);
cristy3ed852e2009-09-05 21:47:34 +00005475 return(MagickTrue);
5476}