]> granicus.if.org Git - imagemagick/blob - magick/cache.c
(no commit message)
[imagemagick] / magick / cache.c
1 /*
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 %                                                                             %
20 %  Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization      %
21 %  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 \f
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"
52 #include "magick/geometry.h"
53 #include "magick/list.h"
54 #include "magick/log.h"
55 #include "magick/magick.h"
56 #include "magick/memory_.h"
57 #include "magick/pixel.h"
58 #include "magick/pixel-private.h"
59 #include "magick/policy.h"
60 #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"
66 #include "magick/string-private.h"
67 #include "magick/thread-private.h"
68 #include "magick/utility.h"
69 #if defined(MAGICKCORE_ZLIB_DELEGATE)
70 #include "zlib.h"
71 #endif
72 \f
73 /*
74   Define declarations.
75 */
76 #define CacheTick(offset,extent)  QuantumTick((MagickOffsetType) offset,extent)
77 \f
78 /*
79   Typedef declarations.
80 */
81 typedef struct _MagickModulo
82 {
83   ssize_t
84     quotient,
85     remainder;
86 } MagickModulo;
87
88 struct _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
106   size_t
107     signature;
108 };
109 \f
110 /*
111   Forward declarations.
112 */
113 #if defined(__cplusplus) || defined(c_plusplus)
114 extern "C" {
115 #endif
116
117 static const IndexPacket
118   *GetVirtualIndexesFromCache(const Image *);
119
120 static const PixelPacket
121   *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122     const ssize_t,const size_t,const size_t,ExceptionInfo *),
123   *GetVirtualPixelsCache(const Image *);
124
125 static MagickBooleanType
126   GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127     PixelPacket *,ExceptionInfo *),
128   GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
129     const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
130   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
137 static PixelPacket
138   *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 *),
142   *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
143     ExceptionInfo *);
144
145 #if defined(__cplusplus) || defined(c_plusplus)
146 }
147 #endif
148 \f
149 /*
150   Global declarations.
151 */
152 static volatile MagickBooleanType
153   instantiate_cache = MagickFalse;
154
155 static SemaphoreInfo
156   *cache_semaphore = (SemaphoreInfo *) NULL;
157
158 static SplayTreeInfo
159   *cache_resources = (SplayTreeInfo *) NULL;
160 \f
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 %
176 %      Cache AcquirePixelCache(const size_t number_threads)
177 %
178 %  A description of each parameter follows:
179 %
180 %    o number_threads: the number of nexus threads.
181 %
182 */
183 MagickExport Cache AcquirePixelCache(const size_t number_threads)
184 {
185   CacheInfo
186     *cache_info;
187
188   cache_info=(CacheInfo *) AcquireMagickMemory(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;
193   cache_info->mode=IOMode;
194   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   cache_info->semaphore=AllocateSemaphoreInfo();
204   cache_info->reference_count=1;
205   cache_info->disk_semaphore=AllocateSemaphoreInfo();
206   cache_info->debug=IsEventLogging();
207   cache_info->signature=MagickSignature;
208   if ((cache_resources == (SplayTreeInfo *) NULL) &&
209       (instantiate_cache == MagickFalse))
210     {
211       if (cache_semaphore == (SemaphoreInfo *) NULL)
212         AcquireSemaphoreInfo(&cache_semaphore);
213       LockSemaphoreInfo(cache_semaphore);
214       if ((cache_resources == (SplayTreeInfo *) NULL) &&
215           (instantiate_cache == MagickFalse))
216         {
217           cache_resources=NewSplayTree((int (*)(const void *,const void *))
218             NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
219           instantiate_cache=MagickTrue;
220         }
221       UnlockSemaphoreInfo(cache_semaphore);
222     }
223   (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
224   return((Cache ) cache_info);
225 }
226 \f
227 /*
228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
229 %                                                                             %
230 %                                                                             %
231 %                                                                             %
232 %   A c q u i r e P i x e l C a c h e N e x u s                               %
233 %                                                                             %
234 %                                                                             %
235 %                                                                             %
236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 %
238 %  AcquirePixelCacheNexus() allocates the NexusInfo structure.
239 %
240 %  The format of the AcquirePixelCacheNexus method is:
241 %
242 %      NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
243 %
244 %  A description of each parameter follows:
245 %
246 %    o number_threads: the number of nexus threads.
247 %
248 */
249 MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
250 {
251   NexusInfo
252     **nexus_info;
253
254   register ssize_t
255     i;
256
257   nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
258     sizeof(*nexus_info));
259   if (nexus_info == (NexusInfo **) NULL)
260     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
261   for (i=0; i < (ssize_t) number_threads; i++)
262   {
263     nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
264     if (nexus_info[i] == (NexusInfo *) NULL)
265       ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266     (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
267     nexus_info[i]->signature=MagickSignature;
268   }
269   return(nexus_info);
270 }
271 \f
272 /*
273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 %                                                                             %
275 %                                                                             %
276 %                                                                             %
277 +   A c q u i r e P i x e l C a c h e P i x e l s                             %
278 %                                                                             %
279 %                                                                             %
280 %                                                                             %
281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282 %
283 %  AcquirePixelCachePixels() returns the pixels associated with the specified
284 %  image.
285 %
286 %  The format of the AcquirePixelCachePixels() method is:
287 %
288 %      const void *AcquirePixelCachePixels(const Image *image,
289 %        MagickSizeType *length,ExceptionInfo *exception)
290 %
291 %  A description of each parameter follows:
292 %
293 %    o image: the image.
294 %
295 %    o length: the pixel cache length.
296 %
297 %    o exception: return any errors or warnings in this structure.
298 %
299 */
300 MagickExport const void *AcquirePixelCachePixels(const Image *image,
301   MagickSizeType *length,ExceptionInfo *exception)
302 {
303   CacheInfo
304     *cache_info;
305
306   assert(image != (const Image *) NULL);
307   assert(image->signature == MagickSignature);
308   assert(exception != (ExceptionInfo *) NULL);
309   assert(exception->signature == MagickSignature);
310   assert(image->cache != (Cache) NULL);
311   cache_info=(CacheInfo *) image->cache;
312   assert(cache_info->signature == MagickSignature);
313   *length=0;
314   if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
315     return((const void *) NULL);
316   *length=cache_info->length;
317   return((const void *) cache_info->pixels);
318 }
319 \f
320 /*
321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322 %                                                                             %
323 %                                                                             %
324 %                                                                             %
325 +   C a c h e C o m p o n e n t G e n e s i s                                 %
326 %                                                                             %
327 %                                                                             %
328 %                                                                             %
329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330 %
331 %  CacheComponentGenesis() instantiates the cache component.
332 %
333 %  The format of the CacheComponentGenesis method is:
334 %
335 %      MagickBooleanType CacheComponentGenesis(void)
336 %
337 */
338 MagickExport MagickBooleanType CacheComponentGenesis(void)
339 {
340   AcquireSemaphoreInfo(&cache_semaphore);
341   return(MagickTrue);
342 }
343 \f
344 /*
345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 %                                                                             %
347 %                                                                             %
348 %                                                                             %
349 +   C a c h e C o m p o n e n t T e r m i n u s                               %
350 %                                                                             %
351 %                                                                             %
352 %                                                                             %
353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354 %
355 %  CacheComponentTerminus() destroys the cache component.
356 %
357 %  The format of the CacheComponentTerminus() method is:
358 %
359 %      CacheComponentTerminus(void)
360 %
361 */
362 MagickExport void CacheComponentTerminus(void)
363 {
364   if (cache_semaphore == (SemaphoreInfo *) NULL)
365     AcquireSemaphoreInfo(&cache_semaphore);
366   LockSemaphoreInfo(cache_semaphore);
367   if (cache_resources != (SplayTreeInfo *) NULL)
368     cache_resources=DestroySplayTree(cache_resources);
369   instantiate_cache=MagickFalse;
370   UnlockSemaphoreInfo(cache_semaphore);
371   DestroySemaphoreInfo(&cache_semaphore);
372 }
373 \f
374 /*
375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376 %                                                                             %
377 %                                                                             %
378 %                                                                             %
379 +   C l i p P i x e l C a c h e N e x u s                                     %
380 %                                                                             %
381 %                                                                             %
382 %                                                                             %
383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384 %
385 %  ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
386 %  mask.  The method returns MagickTrue if the pixel region is clipped,
387 %  otherwise MagickFalse.
388 %
389 %  The format of the ClipPixelCacheNexus() method is:
390 %
391 %      MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
392 %        ExceptionInfo *exception)
393 %
394 %  A description of each parameter follows:
395 %
396 %    o image: the image.
397 %
398 %    o nexus_info: the cache nexus to clip.
399 %
400 %    o exception: return any errors or warnings in this structure.
401 %
402 */
403 static MagickBooleanType ClipPixelCacheNexus(Image *image,
404   NexusInfo *nexus_info,ExceptionInfo *exception)
405 {
406   CacheInfo
407     *cache_info;
408
409   MagickSizeType
410     number_pixels;
411
412   NexusInfo
413     **clip_nexus,
414     **image_nexus;
415
416   register const PixelPacket
417     *restrict r;
418
419   register IndexPacket
420     *restrict nexus_indexes,
421     *restrict indexes;
422
423   register PixelPacket
424     *restrict p,
425     *restrict q;
426
427   register ssize_t
428     i;
429
430   /*
431     Apply clip mask.
432   */
433   if (image->debug != MagickFalse)
434     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
435   if (image->clip_mask == (Image *) NULL)
436     return(MagickFalse);
437   cache_info=(CacheInfo *) image->cache;
438   if (cache_info == (Cache) NULL)
439     return(MagickFalse);
440   image_nexus=AcquirePixelCacheNexus(1);
441   clip_nexus=AcquirePixelCacheNexus(1);
442   if ((image_nexus == (NexusInfo **) NULL) ||
443       (clip_nexus == (NexusInfo **) NULL))
444     ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
445   p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
446     nexus_info->region.width,nexus_info->region.height,image_nexus[0],
447     exception);
448   indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
449   q=nexus_info->pixels;
450   nexus_indexes=nexus_info->indexes;
451   r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
452     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
453     nexus_info->region.height,clip_nexus[0],exception);
454   number_pixels=(MagickSizeType) nexus_info->region.width*
455     nexus_info->region.height;
456   for (i=0; i < (ssize_t) number_pixels; i++)
457   {
458     if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
459       break;
460     if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
461       {
462         SetRedPixelComponent(q,GetRedPixelComponent(p));
463         SetGreenPixelComponent(q,GetGreenPixelComponent(p));
464         SetBluePixelComponent(q,GetBluePixelComponent(p));
465         SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
466         if (cache_info->active_index_channel != MagickFalse)
467           nexus_indexes[i]=indexes[i];
468       }
469     p++;
470     q++;
471     r++;
472   }
473   clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
474   image_nexus=DestroyPixelCacheNexus(image_nexus,1);
475   if (i < (ssize_t) number_pixels)
476     return(MagickFalse);
477   return(MagickTrue);
478 }
479 \f
480 /*
481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482 %                                                                             %
483 %                                                                             %
484 %                                                                             %
485 +   C l o n e P i x e l C a c h e                                             %
486 %                                                                             %
487 %                                                                             %
488 %                                                                             %
489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490 %
491 %  ClonePixelCache() clones a pixel cache.
492 %
493 %  The format of the ClonePixelCache() method is:
494 %
495 %      Cache ClonePixelCache(const Cache cache)
496 %
497 %  A description of each parameter follows:
498 %
499 %    o cache: the pixel cache.
500 %
501 */
502 MagickExport Cache ClonePixelCache(const Cache cache)
503 {
504   CacheInfo
505     *clone_info;
506
507   const CacheInfo
508     *cache_info;
509
510   assert(cache != (const Cache) NULL);
511   cache_info=(const CacheInfo *) cache;
512   assert(cache_info->signature == MagickSignature);
513   if (cache_info->debug != MagickFalse)
514     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
515       cache_info->filename);
516   clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
517   if (clone_info == (Cache) NULL)
518     return((Cache) NULL);
519   clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
520   return((Cache ) clone_info);
521 }
522 \f
523 /*
524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525 %                                                                             %
526 %                                                                             %
527 %                                                                             %
528 +   C l o n e P i x e l C a c h e P i x e l s                                 %
529 %                                                                             %
530 %                                                                             %
531 %                                                                             %
532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
533 %  ClonePixelCachePixels() clones the source pixel cache to the destination
534 %  cache.
535 %
536 %  The format of the ClonePixelCachePixels() method is:
537 %
538 %      MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
539 %        CacheInfo *source_info,ExceptionInfo *exception)
540 %
541 %  A description of each parameter follows:
542 %
543 %    o cache_info: the pixel cache.
544 %
545 %    o source_info: the source pixel cache.
546 %
547 %    o exception: return any errors or warnings in this structure.
548 %
549 */
550
551 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
552 {
553   int
554     status;
555
556   status=(-1);
557   LockSemaphoreInfo(cache_info->disk_semaphore);
558   if (cache_info->file != -1)
559     status=close(cache_info->file);
560   cache_info->file=(-1);
561   RelinquishMagickResource(FileResource,1);
562   UnlockSemaphoreInfo(cache_info->disk_semaphore);
563   return(status == -1 ? MagickFalse : MagickTrue);
564 }
565
566 static void LimitPixelCacheDescriptors(void)
567 {
568   register CacheInfo
569     *p,
570     *q;
571
572   /*
573     Limit # of open file descriptors.
574   */
575   if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
576     return;
577   LockSemaphoreInfo(cache_semaphore);
578   if (cache_resources == (SplayTreeInfo *) NULL)
579     {
580       UnlockSemaphoreInfo(cache_semaphore);
581       return;
582     }
583   ResetSplayTreeIterator(cache_resources);
584   p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
585   while (p != (CacheInfo *) NULL)
586   {
587     if ((p->type == DiskCache) && (p->file != -1))
588       break;
589     p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
590   }
591   for (q=p; p != (CacheInfo *) NULL; )
592   {
593     if ((p->type == DiskCache) && (p->file != -1) &&
594         (p->timestamp < q->timestamp))
595       q=p;
596     p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
597   }
598   if (q != (CacheInfo *) NULL)
599     {
600       /*
601         Close least recently used cache.
602       */
603       (void) close(q->file);
604       q->file=(-1);
605     }
606   UnlockSemaphoreInfo(cache_semaphore);
607 }
608
609 static inline MagickSizeType MagickMax(const MagickSizeType x,
610   const MagickSizeType y)
611 {
612   if (x > y)
613     return(x);
614   return(y);
615 }
616
617 static inline MagickSizeType MagickMin(const MagickSizeType x,
618   const MagickSizeType y)
619 {
620   if (x < y)
621     return(x);
622   return(y);
623 }
624
625 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
626   const MapMode mode)
627 {
628   int
629     file;
630
631   /*
632     Open pixel cache on disk.
633   */
634   LockSemaphoreInfo(cache_info->disk_semaphore);
635   if (cache_info->file != -1)
636     {
637       UnlockSemaphoreInfo(cache_info->disk_semaphore);
638       return(MagickTrue);  /* cache already open */
639     }
640   LimitPixelCacheDescriptors();
641   if (*cache_info->cache_filename == '\0')
642     file=AcquireUniqueFileResource(cache_info->cache_filename);
643   else
644     switch (mode)
645     {
646       case ReadMode:
647       {
648         file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
649         break;
650       }
651       case WriteMode:
652       {
653         file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
654           O_EXCL,S_MODE);
655         if (file == -1)
656           file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
657         break;
658       }
659       case IOMode:
660       default:
661       {
662         file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
663           O_EXCL,S_MODE);
664         if (file == -1)
665           file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
666         break;
667       }
668     }
669   if (file == -1)
670     {
671       UnlockSemaphoreInfo(cache_info->disk_semaphore);
672       return(MagickFalse);
673     }
674   (void) AcquireMagickResource(FileResource,1);
675   cache_info->file=file;
676   cache_info->timestamp=time(0);
677   UnlockSemaphoreInfo(cache_info->disk_semaphore);
678   return(MagickTrue);
679 }
680
681 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682   const MagickOffsetType offset,const MagickSizeType length,
683   unsigned char *restrict buffer)
684 {
685   register MagickOffsetType
686     i;
687
688   ssize_t
689     count;
690
691   cache_info->timestamp=time(0);
692 #if !defined(MAGICKCORE_HAVE_PREAD)
693   LockSemaphoreInfo(cache_info->disk_semaphore);
694   if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
695     {
696       UnlockSemaphoreInfo(cache_info->disk_semaphore);
697       return((MagickOffsetType) -1);
698     }
699 #endif
700   count=0;
701   for (i=0; i < (MagickOffsetType) length; i+=count)
702   {
703 #if !defined(MAGICKCORE_HAVE_PREAD)
704     count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705       (MagickSizeType) SSIZE_MAX));
706 #else
707     count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708       (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
709 #endif
710     if (count > 0)
711       continue;
712     count=0;
713     if (errno != EINTR)
714       {
715         i=(-1);
716         break;
717       }
718   }
719 #if !defined(MAGICKCORE_HAVE_PREAD)
720   UnlockSemaphoreInfo(cache_info->disk_semaphore);
721 #endif
722   return(i);
723 }
724
725 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726   const MagickOffsetType offset,const MagickSizeType length,
727   const unsigned char *restrict buffer)
728 {
729   register MagickOffsetType
730     i;
731
732   ssize_t
733     count;
734
735   cache_info->timestamp=time(0);
736 #if !defined(MAGICKCORE_HAVE_PWRITE)
737   LockSemaphoreInfo(cache_info->disk_semaphore);
738   if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
739     {
740       UnlockSemaphoreInfo(cache_info->disk_semaphore);
741       return((MagickOffsetType) -1);
742     }
743 #endif
744   count=0;
745   for (i=0; i < (MagickOffsetType) length; i+=count)
746   {
747 #if !defined(MAGICKCORE_HAVE_PWRITE)
748     count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749       (MagickSizeType) SSIZE_MAX));
750 #else
751     count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752       (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
753 #endif
754     if (count > 0)
755       continue;
756     count=0;
757     if (errno != EINTR)
758       {
759         i=(-1);
760         break;
761       }
762   }
763 #if !defined(MAGICKCORE_HAVE_PWRITE)
764   UnlockSemaphoreInfo(cache_info->disk_semaphore);
765 #endif
766   return(i);
767 }
768
769 static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
770   CacheInfo *cache_info,ExceptionInfo *exception)
771 {
772   MagickOffsetType
773     count,
774     offset,
775     source_offset;
776
777   MagickSizeType
778     length;
779
780   register PixelPacket
781     *restrict pixels;
782
783   register ssize_t
784     y;
785
786   size_t
787     columns,
788     rows;
789
790   if (cache_info->debug != MagickFalse)
791     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792   if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
793     {
794       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795         clone_info->cache_filename);
796       return(MagickFalse);
797     }
798   if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
799     {
800       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
801         cache_info->cache_filename);
802       return(MagickFalse);
803     }
804   columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
805   rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
806   if ((clone_info->active_index_channel != MagickFalse) &&
807       (cache_info->active_index_channel != MagickFalse))
808     {
809       register IndexPacket
810         *indexes;
811
812       /*
813         Clone cache indexes.
814       */
815       length=MagickMax(clone_info->columns,cache_info->columns)*
816         sizeof(*indexes);
817       indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
818       if (indexes == (IndexPacket *) NULL)
819         {
820           (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
821             "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
822           return(MagickFalse);
823         }
824       (void) ResetMagickMemory(indexes,0,(size_t) length);
825       length=columns*sizeof(*indexes);
826       source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
827         sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
828       offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
829         sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
830       for (y=0; y < (ssize_t) rows; y++)
831       {
832         source_offset-=cache_info->columns*sizeof(*indexes);
833         count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
834           length,(unsigned char *) indexes);
835         if ((MagickSizeType) count != length)
836           break;
837         offset-=clone_info->columns*sizeof(*indexes);
838         count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839           (unsigned char *) indexes);
840         if ((MagickSizeType) count != length)
841           break;
842       }
843       if (y < (ssize_t) rows)
844         {
845           indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
846           ThrowFileException(exception,CacheError,"UnableToCloneCache",
847             cache_info->cache_filename);
848           return(MagickFalse);
849         }
850       if (clone_info->columns > cache_info->columns)
851         {
852           length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
853           (void) ResetMagickMemory(indexes,0,(size_t) length);
854           offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
855             sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
856           for (y=0; y < (ssize_t) rows; y++)
857           {
858             offset-=clone_info->columns*sizeof(*indexes);
859             count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
860               length,(unsigned char *) indexes);
861             if ((MagickSizeType) count != length)
862               break;
863           }
864           if (y < (ssize_t) rows)
865             {
866               indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867               ThrowFileException(exception,CacheError,"UnableToCloneCache",
868                 cache_info->cache_filename);
869               return(MagickFalse);
870             }
871         }
872       indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
873     }
874   /*
875     Clone cache pixels.
876   */
877   length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
878   pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
879   if (pixels == (PixelPacket *) NULL)
880     {
881       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
882         "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
883       return(MagickFalse);
884     }
885   (void) ResetMagickMemory(pixels,0,(size_t) length);
886   length=columns*sizeof(*pixels);
887   source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
888   offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
889   for (y=0; y < (ssize_t) rows; y++)
890   {
891     source_offset-=cache_info->columns*sizeof(*pixels);
892     count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
893       length,(unsigned char *) pixels);
894     if ((MagickSizeType) count != length)
895       break;
896     offset-=clone_info->columns*sizeof(*pixels);
897     count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898       (unsigned char *) pixels);
899     if ((MagickSizeType) count != length)
900       break;
901   }
902   if (y < (ssize_t) rows)
903     {
904       pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
905       ThrowFileException(exception,CacheError,"UnableToCloneCache",
906         cache_info->cache_filename);
907       return(MagickFalse);
908     }
909   if (clone_info->columns > cache_info->columns)
910     {
911       offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
912         sizeof(*pixels);
913       length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914       (void) ResetMagickMemory(pixels,0,(size_t) length);
915       for (y=0; y < (ssize_t) rows; y++)
916       {
917         offset-=clone_info->columns*sizeof(*pixels);
918         count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919           (unsigned char *) pixels);
920         if ((MagickSizeType) count != length)
921           break;
922       }
923       if (y < (ssize_t) rows)
924         {
925           pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926           ThrowFileException(exception,CacheError,"UnableToCloneCache",
927             cache_info->cache_filename);
928           return(MagickFalse);
929         }
930     }
931   pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
932   return(MagickTrue);
933 }
934
935 static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
936   CacheInfo *cache_info,ExceptionInfo *exception)
937 {
938   MagickOffsetType
939     count,
940     offset;
941
942   MagickSizeType
943     length;
944
945   register PixelPacket
946     *restrict pixels,
947     *restrict q;
948
949   register ssize_t
950     y;
951
952   size_t
953     columns,
954     rows;
955
956   if (cache_info->debug != MagickFalse)
957     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
958   if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
959     {
960       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
961         cache_info->cache_filename);
962       return(MagickFalse);
963     }
964   columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
965   rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
966   if ((clone_info->active_index_channel != MagickFalse) &&
967       (cache_info->active_index_channel != MagickFalse))
968     {
969       register IndexPacket
970         *indexes,
971         *q;
972
973       /*
974         Clone cache indexes.
975       */
976       length=MagickMax(clone_info->columns,cache_info->columns)*
977         sizeof(*indexes);
978       indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
979       if (indexes == (IndexPacket *) NULL)
980         {
981           (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982             "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
983           return(MagickFalse);
984         }
985       (void) ResetMagickMemory(indexes,0,(size_t) length);
986       length=columns*sizeof(IndexPacket);
987       offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988         sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
989       q=clone_info->indexes+clone_info->columns*rows;
990       for (y=0; y < (ssize_t) rows; y++)
991       {
992         offset-=cache_info->columns*sizeof(IndexPacket);
993         count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994           length,(unsigned char *) indexes);
995         if ((MagickSizeType) count != length)
996           break;
997         q-=clone_info->columns;
998         (void) memcpy(q,indexes,(size_t) length);
999         if ((MagickSizeType) count != length)
1000           break;
1001       }
1002       if (y < (ssize_t) rows)
1003         {
1004           indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1005           ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006             cache_info->cache_filename);
1007           return(MagickFalse);
1008         }
1009       indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1010     }
1011   /*
1012     Clone cache pixels.
1013   */
1014   length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1015   pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1016   if (pixels == (PixelPacket *) NULL)
1017     {
1018       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1019         "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1020       return(MagickFalse);
1021     }
1022   (void) ResetMagickMemory(pixels,0,(size_t) length);
1023   length=columns*sizeof(*pixels);
1024   offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1025   q=clone_info->pixels+clone_info->columns*rows;
1026   for (y=0; y < (ssize_t) rows; y++)
1027   {
1028     offset-=cache_info->columns*sizeof(*pixels);
1029     count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030       (unsigned char *) pixels);
1031     if ((MagickSizeType) count != length)
1032       break;
1033     q-=clone_info->columns;
1034     (void) memcpy(q,pixels,(size_t) length);
1035   }
1036   if (y < (ssize_t) rows)
1037     {
1038       pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1039       ThrowFileException(exception,CacheError,"UnableToCloneCache",
1040         cache_info->cache_filename);
1041       return(MagickFalse);
1042     }
1043   pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1044   return(MagickTrue);
1045 }
1046
1047 static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1048   CacheInfo *cache_info,ExceptionInfo *exception)
1049 {
1050   MagickOffsetType
1051     count,
1052     offset;
1053
1054   MagickSizeType
1055     length;
1056
1057   register PixelPacket
1058     *restrict p,
1059     *restrict pixels;
1060
1061   register ssize_t
1062     y;
1063
1064   size_t
1065     columns,
1066     rows;
1067
1068   if (cache_info->debug != MagickFalse)
1069     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1070   if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1071     {
1072       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1073         clone_info->cache_filename);
1074       return(MagickFalse);
1075     }
1076   columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1077   rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1078   if ((clone_info->active_index_channel != MagickFalse) &&
1079       (cache_info->active_index_channel != MagickFalse))
1080     {
1081       register IndexPacket
1082         *p,
1083         *indexes;
1084
1085       /*
1086         Clone cache indexes.
1087       */
1088       length=MagickMax(clone_info->columns,cache_info->columns)*
1089         sizeof(*indexes);
1090       indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1091       if (indexes == (IndexPacket *) NULL)
1092         {
1093           (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1094             "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1095           return(MagickFalse);
1096         }
1097       (void) ResetMagickMemory(indexes,0,(size_t) length);
1098       length=columns*sizeof(*indexes);
1099       p=cache_info->indexes+cache_info->columns*rows;
1100       offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101         sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
1102       for (y=0; y < (ssize_t) rows; y++)
1103       {
1104         p-=cache_info->columns;
1105         (void) memcpy(indexes,p,(size_t) length);
1106         offset-=clone_info->columns*sizeof(*indexes);
1107         count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1108           (unsigned char *) indexes);
1109         if ((MagickSizeType) count != length)
1110           break;
1111       }
1112       if (y < (ssize_t) rows)
1113         {
1114           indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115           ThrowFileException(exception,CacheError,"UnableToCloneCache",
1116             cache_info->cache_filename);
1117           return(MagickFalse);
1118         }
1119       if (clone_info->columns > cache_info->columns)
1120         {
1121           length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1122           (void) ResetMagickMemory(indexes,0,(size_t) length);
1123           offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124             sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
1125           for (y=0; y < (ssize_t) rows; y++)
1126           {
1127             offset-=clone_info->columns*sizeof(*indexes);
1128             count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129               length,(unsigned char *) indexes);
1130             if ((MagickSizeType) count != length)
1131               break;
1132           }
1133           if (y < (ssize_t) rows)
1134             {
1135               indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136               ThrowFileException(exception,CacheError,"UnableToCloneCache",
1137                 cache_info->cache_filename);
1138               return(MagickFalse);
1139             }
1140         }
1141       indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1142     }
1143   /*
1144     Clone cache pixels.
1145   */
1146   length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1147   pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1148   if (pixels == (PixelPacket *) NULL)
1149     {
1150       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1151         "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1152       return(MagickFalse);
1153     }
1154   (void) ResetMagickMemory(pixels,0,(size_t) length);
1155   length=columns*sizeof(*pixels);
1156   p=cache_info->pixels+cache_info->columns*rows;
1157   offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
1158   for (y=0; y < (ssize_t) rows; y++)
1159   {
1160     p-=cache_info->columns;
1161     (void) memcpy(pixels,p,(size_t) length);
1162     offset-=clone_info->columns*sizeof(*pixels);
1163     count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1164       (unsigned char *) pixels);
1165     if ((MagickSizeType) count != length)
1166       break;
1167   }
1168   if (y < (ssize_t) rows)
1169     {
1170       pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1171       ThrowFileException(exception,CacheError,"UnableToCloneCache",
1172         cache_info->cache_filename);
1173       return(MagickFalse);
1174     }
1175   if (clone_info->columns > cache_info->columns)
1176     {
1177       offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1178         sizeof(*pixels);
1179       length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1180       (void) ResetMagickMemory(pixels,0,(size_t) length);
1181       for (y=0; y < (ssize_t) rows; y++)
1182       {
1183         offset-=clone_info->columns*sizeof(*pixels);
1184         count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1185           (unsigned char *) pixels);
1186         if ((MagickSizeType) count != length)
1187           break;
1188       }
1189       if (y < (ssize_t) rows)
1190         {
1191           pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192           ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193             cache_info->cache_filename);
1194           return(MagickFalse);
1195         }
1196     }
1197   pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1198   return(MagickTrue);
1199 }
1200
1201 static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202   CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1203 {
1204   register PixelPacket
1205     *restrict pixels,
1206     *restrict source_pixels;
1207
1208   register ssize_t
1209     y;
1210
1211   size_t
1212     columns,
1213     length,
1214     rows;
1215
1216   if (cache_info->debug != MagickFalse)
1217     (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
1218   columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219   rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1220   if ((clone_info->active_index_channel != MagickFalse) &&
1221       (cache_info->active_index_channel != MagickFalse))
1222     {
1223       register IndexPacket
1224         *indexes,
1225         *source_indexes;
1226
1227       /*
1228         Clone cache indexes.
1229       */
1230       length=columns*sizeof(*indexes);
1231       if (clone_info->columns == cache_info->columns)
1232         (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
1233       else
1234         {
1235           source_indexes=cache_info->indexes+cache_info->columns*rows;
1236           indexes=clone_info->indexes+clone_info->columns*rows;
1237           for (y=0; y < (ssize_t) rows; y++)
1238           {
1239             source_indexes-=cache_info->columns;
1240             indexes-=clone_info->columns;
1241             (void) memcpy(indexes,source_indexes,length);
1242           }
1243           if (clone_info->columns > cache_info->columns)
1244             {
1245               length=(clone_info->columns-cache_info->columns)*
1246                 sizeof(*indexes);
1247               indexes=clone_info->indexes+clone_info->columns*rows+
1248                 cache_info->columns;
1249               for (y=0; y < (ssize_t) rows; y++)
1250               {
1251                 indexes-=clone_info->columns;
1252                 (void) ResetMagickMemory(indexes,0,length);
1253               }
1254             }
1255         }
1256     }
1257   /*
1258     Clone cache pixels.
1259   */
1260   length=columns*sizeof(*pixels);
1261   if (clone_info->columns == cache_info->columns)
1262     (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
1263   else
1264     {
1265       source_pixels=cache_info->pixels+cache_info->columns*rows;
1266       pixels=clone_info->pixels+clone_info->columns*rows;
1267       for (y=0; y < (ssize_t) rows; y++)
1268       {
1269         source_pixels-=cache_info->columns;
1270         pixels-=clone_info->columns;
1271         (void) memcpy(pixels,source_pixels,length);
1272       }
1273       if (clone_info->columns > cache_info->columns)
1274         {
1275           length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1276           pixels=clone_info->pixels+clone_info->columns*rows+
1277             cache_info->columns;
1278           for (y=0; y < (ssize_t) rows; y++)
1279           {
1280             pixels-=clone_info->columns;
1281             (void) ResetMagickMemory(pixels,0,length);
1282           }
1283         }
1284     }
1285   return(MagickTrue);
1286 }
1287
1288 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1289   CacheInfo *cache_info,ExceptionInfo *exception)
1290 {
1291   if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1292     return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1293   if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1294     return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1295   if (cache_info->type == DiskCache)
1296     return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1297   return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1298 }
1299 \f
1300 /*
1301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302 %                                                                             %
1303 %                                                                             %
1304 %                                                                             %
1305 +   C l o n e P i x e l C a c h e M e t h o d s                               %
1306 %                                                                             %
1307 %                                                                             %
1308 %                                                                             %
1309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310 %
1311 %  ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1312 %  another.
1313 %
1314 %  The format of the ClonePixelCacheMethods() method is:
1315 %
1316 %      void ClonePixelCacheMethods(Cache clone,const Cache cache)
1317 %
1318 %  A description of each parameter follows:
1319 %
1320 %    o clone: Specifies a pointer to a Cache structure.
1321 %
1322 %    o cache: the pixel cache.
1323 %
1324 */
1325 MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1326 {
1327   CacheInfo
1328     *cache_info,
1329     *source_info;
1330
1331   assert(clone != (Cache) NULL);
1332   source_info=(CacheInfo *) clone;
1333   assert(source_info->signature == MagickSignature);
1334   if (source_info->debug != MagickFalse)
1335     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1336       source_info->filename);
1337   assert(cache != (Cache) NULL);
1338   cache_info=(CacheInfo *) cache;
1339   assert(cache_info->signature == MagickSignature);
1340   source_info->methods=cache_info->methods;
1341 }
1342 \f
1343 /*
1344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345 %                                                                             %
1346 %                                                                             %
1347 %                                                                             %
1348 +   D e s t r o y I m a g e P i x e l C a c h e                               %
1349 %                                                                             %
1350 %                                                                             %
1351 %                                                                             %
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353 %
1354 %  DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1355 %
1356 %  The format of the DestroyImagePixelCache() method is:
1357 %
1358 %      void DestroyImagePixelCache(Image *image)
1359 %
1360 %  A description of each parameter follows:
1361 %
1362 %    o image: the image.
1363 %
1364 */
1365 static void DestroyImagePixelCache(Image *image)
1366 {
1367   assert(image != (Image *) NULL);
1368   assert(image->signature == MagickSignature);
1369   if (image->debug != MagickFalse)
1370     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1371   if (image->cache == (void *) NULL)
1372     return;
1373   image->cache=DestroyPixelCache(image->cache);
1374 }
1375 \f
1376 /*
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378 %                                                                             %
1379 %                                                                             %
1380 %                                                                             %
1381 +   D e s t r o y I m a g e P i x e l s                                       %
1382 %                                                                             %
1383 %                                                                             %
1384 %                                                                             %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1386 %
1387 %  DestroyImagePixels() deallocates memory associated with the pixel cache.
1388 %
1389 %  The format of the DestroyImagePixels() method is:
1390 %
1391 %      void DestroyImagePixels(Image *image)
1392 %
1393 %  A description of each parameter follows:
1394 %
1395 %    o image: the image.
1396 %
1397 */
1398 MagickExport void DestroyImagePixels(Image *image)
1399 {
1400   CacheInfo
1401     *cache_info;
1402
1403   assert(image != (const Image *) NULL);
1404   assert(image->signature == MagickSignature);
1405   if (image->debug != MagickFalse)
1406     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1407   assert(image->cache != (Cache) NULL);
1408   cache_info=(CacheInfo *) image->cache;
1409   assert(cache_info->signature == MagickSignature);
1410   if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1411     {
1412       cache_info->methods.destroy_pixel_handler(image);
1413       return;
1414     }
1415   image->cache=DestroyPixelCache(image->cache);
1416 }
1417 \f
1418 /*
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420 %                                                                             %
1421 %                                                                             %
1422 %                                                                             %
1423 +   D e s t r o y P i x e l C a c h e                                         %
1424 %                                                                             %
1425 %                                                                             %
1426 %                                                                             %
1427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428 %
1429 %  DestroyPixelCache() deallocates memory associated with the pixel cache.
1430 %
1431 %  The format of the DestroyPixelCache() method is:
1432 %
1433 %      Cache DestroyPixelCache(Cache cache)
1434 %
1435 %  A description of each parameter follows:
1436 %
1437 %    o cache: the pixel cache.
1438 %
1439 */
1440
1441 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1442 {
1443   switch (cache_info->type)
1444   {
1445     case MemoryCache:
1446     {
1447       if (cache_info->mapped == MagickFalse)
1448         cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1449           cache_info->pixels);
1450       else
1451         cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1452           (size_t) cache_info->length);
1453       RelinquishMagickResource(MemoryResource,cache_info->length);
1454       break;
1455     }
1456     case MapCache:
1457     {
1458       cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1459         cache_info->length);
1460       RelinquishMagickResource(MapResource,cache_info->length);
1461     }
1462     case DiskCache:
1463     {
1464       if (cache_info->file != -1)
1465         (void) ClosePixelCacheOnDisk(cache_info);
1466       RelinquishMagickResource(DiskResource,cache_info->length);
1467       break;
1468     }
1469     default:
1470       break;
1471   }
1472   cache_info->type=UndefinedCache;
1473   cache_info->mapped=MagickFalse;
1474   cache_info->indexes=(IndexPacket *) NULL;
1475 }
1476
1477 MagickExport Cache DestroyPixelCache(Cache cache)
1478 {
1479   CacheInfo
1480     *cache_info;
1481
1482   assert(cache != (Cache) NULL);
1483   cache_info=(CacheInfo *) cache;
1484   assert(cache_info->signature == MagickSignature);
1485   if (cache_info->debug != MagickFalse)
1486     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1487       cache_info->filename);
1488   LockSemaphoreInfo(cache_info->semaphore);
1489   cache_info->reference_count--;
1490   if (cache_info->reference_count != 0)
1491     {
1492       UnlockSemaphoreInfo(cache_info->semaphore);
1493       return((Cache) NULL);
1494     }
1495   UnlockSemaphoreInfo(cache_info->semaphore);
1496   if (cache_resources != (SplayTreeInfo *) NULL)
1497     (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1498   if (cache_info->debug != MagickFalse)
1499     {
1500       char
1501         message[MaxTextExtent];
1502
1503       (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1504         cache_info->filename);
1505       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1506     }
1507   if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1508       (cache_info->type != DiskCache)))
1509     RelinquishPixelCachePixels(cache_info);
1510   else
1511     {
1512       RelinquishPixelCachePixels(cache_info);
1513       (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1514     }
1515   *cache_info->cache_filename='\0';
1516   if (cache_info->nexus_info != (NexusInfo **) NULL)
1517     cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1518       cache_info->number_threads);
1519   if (cache_info->random_info != (RandomInfo *) NULL)
1520     cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1521   if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1522     DestroySemaphoreInfo(&cache_info->disk_semaphore);
1523   if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1524     DestroySemaphoreInfo(&cache_info->semaphore);
1525   cache_info->signature=(~MagickSignature);
1526   cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1527   cache=(Cache) NULL;
1528   return(cache);
1529 }
1530 \f
1531 /*
1532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533 %                                                                             %
1534 %                                                                             %
1535 %                                                                             %
1536 +   D e s t r o y P i x e l C a c h e N e x u s                               %
1537 %                                                                             %
1538 %                                                                             %
1539 %                                                                             %
1540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541 %
1542 %  DestroyPixelCacheNexus() destroys a pixel cache nexus.
1543 %
1544 %  The format of the DestroyPixelCacheNexus() method is:
1545 %
1546 %      NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1547 %        const size_t number_threads)
1548 %
1549 %  A description of each parameter follows:
1550 %
1551 %    o nexus_info: the nexus to destroy.
1552 %
1553 %    o number_threads: the number of nexus threads.
1554 %
1555 */
1556
1557 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1558 {
1559   if (nexus_info->mapped == MagickFalse)
1560     (void) RelinquishMagickMemory(nexus_info->cache);
1561   else
1562     (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1563   nexus_info->cache=(PixelPacket *) NULL;
1564   nexus_info->pixels=(PixelPacket *) NULL;
1565   nexus_info->indexes=(IndexPacket *) NULL;
1566   nexus_info->length=0;
1567   nexus_info->mapped=MagickFalse;
1568 }
1569
1570 MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1571   const size_t number_threads)
1572 {
1573   register ssize_t
1574     i;
1575
1576   assert(nexus_info != (NexusInfo **) NULL);
1577   for (i=0; i < (ssize_t) number_threads; i++)
1578   {
1579     if (nexus_info[i]->cache != (PixelPacket *) NULL)
1580       RelinquishCacheNexusPixels(nexus_info[i]);
1581     nexus_info[i]->signature=(~MagickSignature);
1582     nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1583   }
1584   nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1585   return(nexus_info);
1586 }
1587 \f
1588 /*
1589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590 %                                                                             %
1591 %                                                                             %
1592 %                                                                             %
1593 +   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                   %
1594 %                                                                             %
1595 %                                                                             %
1596 %                                                                             %
1597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598 %
1599 %  GetAuthenticIndexesFromCache() returns the indexes associated with the last
1600 %  call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1601 %
1602 %  The format of the GetAuthenticIndexesFromCache() method is:
1603 %
1604 %      IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1605 %
1606 %  A description of each parameter follows:
1607 %
1608 %    o image: the image.
1609 %
1610 */
1611 static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1612 {
1613   CacheInfo
1614     *cache_info;
1615
1616   const int
1617     id = GetOpenMPThreadId();
1618
1619   assert(image != (const Image *) NULL);
1620   assert(image->signature == MagickSignature);
1621   assert(image->cache != (Cache) NULL);
1622   cache_info=(CacheInfo *) image->cache;
1623   assert(cache_info->signature == MagickSignature);
1624   assert(id < (int) cache_info->number_threads);
1625   return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
1626 }
1627 \f
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 */
1653 MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1654 {
1655   CacheInfo
1656     *cache_info;
1657
1658   const int
1659     id = GetOpenMPThreadId();
1660
1661   assert(image != (const Image *) NULL);
1662   assert(image->signature == MagickSignature);
1663   assert(image->cache != (Cache) NULL);
1664   cache_info=(CacheInfo *) image->cache;
1665   assert(cache_info->signature == MagickSignature);
1666   if (cache_info->methods.get_authentic_indexes_from_handler !=
1667        (GetAuthenticIndexesFromHandler) NULL)
1668     return(cache_info->methods.get_authentic_indexes_from_handler(image));
1669   assert(id < (int) cache_info->number_threads);
1670   return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
1671 }
1672 \f
1673 /*
1674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675 %                                                                             %
1676 %                                                                             %
1677 %                                                                             %
1678 +   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                     %
1679 %                                                                             %
1680 %                                                                             %
1681 %                                                                             %
1682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683 %
1684 %  GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1685 %  disk pixel cache as defined by the geometry parameters.   A pointer to the
1686 %  pixels is returned if the pixels are transferred, otherwise a NULL is
1687 %  returned.
1688 %
1689 %  The format of the GetAuthenticPixelCacheNexus() method is:
1690 %
1691 %      PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1692 %        const ssize_t y,const size_t columns,const size_t rows,
1693 %        NexusInfo *nexus_info,ExceptionInfo *exception)
1694 %
1695 %  A description of each parameter follows:
1696 %
1697 %    o image: the image.
1698 %
1699 %    o x,y,columns,rows:  These values define the perimeter of a region of
1700 %      pixels.
1701 %
1702 %    o nexus_info: the cache nexus to return.
1703 %
1704 %    o exception: return any errors or warnings in this structure.
1705 %
1706 */
1707
1708 static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1709   NexusInfo *nexus_info)
1710 {
1711   MagickOffsetType
1712     offset;
1713
1714   if (cache_info->type == PingCache)
1715     return(MagickTrue);
1716   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1717     nexus_info->region.x;
1718   return(nexus_info->pixels == (cache_info->pixels+offset) ? MagickTrue :
1719     MagickFalse);
1720 }
1721
1722 MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1723   const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1724   NexusInfo *nexus_info,ExceptionInfo *exception)
1725 {
1726   CacheInfo
1727     *cache_info;
1728
1729   PixelPacket
1730     *pixels;
1731
1732   /*
1733     Transfer pixels from the cache.
1734   */
1735   assert(image != (Image *) NULL);
1736   assert(image->signature == MagickSignature);
1737   pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1738   if (pixels == (PixelPacket *) NULL)
1739     return((PixelPacket *) NULL);
1740   cache_info=(CacheInfo *) image->cache;
1741   assert(cache_info->signature == MagickSignature);
1742   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1743     return(pixels);
1744   if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1745     return((PixelPacket *) NULL);
1746   if (cache_info->active_index_channel != MagickFalse)
1747     if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1748       return((PixelPacket *) NULL);
1749   return(pixels);
1750 }
1751 \f
1752 /*
1753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1754 %                                                                             %
1755 %                                                                             %
1756 %                                                                             %
1757 +   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                     %
1758 %                                                                             %
1759 %                                                                             %
1760 %                                                                             %
1761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1762 %
1763 %  GetAuthenticPixelsFromCache() returns the pixels associated with the last
1764 %  call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1765 %
1766 %  The format of the GetAuthenticPixelsFromCache() method is:
1767 %
1768 %      PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1769 %
1770 %  A description of each parameter follows:
1771 %
1772 %    o image: the image.
1773 %
1774 */
1775 static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1776 {
1777   CacheInfo
1778     *cache_info;
1779
1780   const int
1781     id = GetOpenMPThreadId();
1782
1783   assert(image != (const Image *) NULL);
1784   assert(image->signature == MagickSignature);
1785   assert(image->cache != (Cache) NULL);
1786   cache_info=(CacheInfo *) image->cache;
1787   assert(cache_info->signature == MagickSignature);
1788   assert(id < (int) cache_info->number_threads);
1789   return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1790 }
1791 \f
1792 /*
1793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1794 %                                                                             %
1795 %                                                                             %
1796 %                                                                             %
1797 %   G e t A u t h e n t i c P i x e l Q u e u e                               %
1798 %                                                                             %
1799 %                                                                             %
1800 %                                                                             %
1801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802 %
1803 %  GetAuthenticPixelQueue() returns the authentic pixels associated with the
1804 %  last call to QueueAuthenticPixels() or GetAuthenticPixels().
1805 %
1806 %  The format of the GetAuthenticPixelQueue() method is:
1807 %
1808 %      PixelPacket *GetAuthenticPixelQueue(const Image image)
1809 %
1810 %  A description of each parameter follows:
1811 %
1812 %    o image: the image.
1813 %
1814 */
1815 MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1816 {
1817   CacheInfo
1818     *cache_info;
1819
1820   const int
1821     id = GetOpenMPThreadId();
1822
1823   assert(image != (const Image *) NULL);
1824   assert(image->signature == MagickSignature);
1825   assert(image->cache != (Cache) NULL);
1826   cache_info=(CacheInfo *) image->cache;
1827   assert(cache_info->signature == MagickSignature);
1828   if (cache_info->methods.get_authentic_pixels_from_handler !=
1829        (GetAuthenticPixelsFromHandler) NULL)
1830     return(cache_info->methods.get_authentic_pixels_from_handler(image));
1831   assert(id < (int) cache_info->number_threads);
1832   return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1833 }
1834 \f
1835 /*
1836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1837 %                                                                             %
1838 %                                                                             %
1839 %                                                                             %
1840 %   G e t A u t h e n t i c P i x e l s                                       %
1841 %                                                                             %
1842 %                                                                             %
1843 %                                                                             %
1844 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1845 %
1846 %  GetAuthenticPixels() obtains a pixel region for read/write access. If the
1847 %  region is successfully accessed, a pointer to a PixelPacket array
1848 %  representing the region is returned, otherwise NULL is returned.
1849 %
1850 %  The returned pointer may point to a temporary working copy of the pixels
1851 %  or it may point to the original pixels in memory. Performance is maximized
1852 %  if the selected region is part of one row, or one or more full rows, since
1853 %  then there is opportunity to access the pixels in-place (without a copy)
1854 %  if the image is in memory, or in a memory-mapped file. The returned pointer
1855 %  must *never* be deallocated by the user.
1856 %
1857 %  Pixels accessed via the returned pointer represent a simple array of type
1858 %  PixelPacket. If the image type is CMYK or if the storage class is
1859 %  PseduoClass, call GetAuthenticIndexQueue() after invoking
1860 %  GetAuthenticPixels() to obtain the black color component or colormap indexes
1861 %  (of type IndexPacket) corresponding to the region.  Once the PixelPacket
1862 %  (and/or IndexPacket) array has been updated, the changes must be saved back
1863 %  to the underlying image using SyncAuthenticPixels() or they may be lost.
1864 %
1865 %  The format of the GetAuthenticPixels() method is:
1866 %
1867 %      PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1868 %        const ssize_t y,const size_t columns,const size_t rows,
1869 %        ExceptionInfo *exception)
1870 %
1871 %  A description of each parameter follows:
1872 %
1873 %    o image: the image.
1874 %
1875 %    o x,y,columns,rows:  These values define the perimeter of a region of
1876 %      pixels.
1877 %
1878 %    o exception: return any errors or warnings in this structure.
1879 %
1880 */
1881 MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1882   const ssize_t y,const size_t columns,const size_t rows,
1883   ExceptionInfo *exception)
1884 {
1885   CacheInfo
1886     *cache_info;
1887
1888   const int
1889     id = GetOpenMPThreadId();
1890
1891   assert(image != (Image *) NULL);
1892   assert(image->signature == MagickSignature);
1893   assert(image->cache != (Cache) NULL);
1894   cache_info=(CacheInfo *) image->cache;
1895   assert(cache_info->signature == MagickSignature);
1896   if (cache_info->methods.get_authentic_pixels_handler !=
1897        (GetAuthenticPixelsHandler) NULL)
1898     return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1899       rows,exception));
1900   assert(id < (int) cache_info->number_threads);
1901   return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1902     cache_info->nexus_info[id],exception));
1903 }
1904 \f
1905 /*
1906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1907 %                                                                             %
1908 %                                                                             %
1909 %                                                                             %
1910 +   G e t A u t h e n t i c P i x e l s C a c h e                             %
1911 %                                                                             %
1912 %                                                                             %
1913 %                                                                             %
1914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1915 %
1916 %  GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1917 %  as defined by the geometry parameters.   A pointer to the pixels is returned
1918 %  if the pixels are transferred, otherwise a NULL is returned.
1919 %
1920 %  The format of the GetAuthenticPixelsCache() method is:
1921 %
1922 %      PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1923 %        const ssize_t y,const size_t columns,const size_t rows,
1924 %        ExceptionInfo *exception)
1925 %
1926 %  A description of each parameter follows:
1927 %
1928 %    o image: the image.
1929 %
1930 %    o x,y,columns,rows:  These values define the perimeter of a region of
1931 %      pixels.
1932 %
1933 %    o exception: return any errors or warnings in this structure.
1934 %
1935 */
1936 static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1937   const ssize_t y,const size_t columns,const size_t rows,
1938   ExceptionInfo *exception)
1939 {
1940   CacheInfo
1941     *cache_info;
1942
1943   const int
1944     id = GetOpenMPThreadId();
1945
1946   assert(image != (const Image *) NULL);
1947   assert(image->signature == MagickSignature);
1948   assert(image->cache != (Cache) NULL);
1949   cache_info=(CacheInfo *) image->cache;
1950   if (cache_info == (Cache) NULL)
1951     return((PixelPacket *) NULL);
1952   assert(cache_info->signature == MagickSignature);
1953   assert(id < (int) cache_info->number_threads);
1954   return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1955     cache_info->nexus_info[id],exception));
1956 }
1957 \f
1958 /*
1959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1960 %                                                                             %
1961 %                                                                             %
1962 %                                                                             %
1963 +   G e t I m a g e E x t e n t                                               %
1964 %                                                                             %
1965 %                                                                             %
1966 %                                                                             %
1967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1968 %
1969 %  GetImageExtent() returns the extent of the pixels associated with the
1970 %  last call to QueueAuthenticPixels() or GetAuthenticPixels().
1971 %
1972 %  The format of the GetImageExtent() method is:
1973 %
1974 %      MagickSizeType GetImageExtent(const Image *image)
1975 %
1976 %  A description of each parameter follows:
1977 %
1978 %    o image: the image.
1979 %
1980 */
1981 MagickExport MagickSizeType GetImageExtent(const Image *image)
1982 {
1983   CacheInfo
1984     *cache_info;
1985
1986   const int
1987     id = GetOpenMPThreadId();
1988
1989   assert(image != (Image *) NULL);
1990   assert(image->signature == MagickSignature);
1991   if (image->debug != MagickFalse)
1992     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1993   assert(image->cache != (Cache) NULL);
1994   cache_info=(CacheInfo *) image->cache;
1995   assert(cache_info->signature == MagickSignature);
1996   assert(id < (int) cache_info->number_threads);
1997   return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1998 }
1999 \f
2000 /*
2001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2002 %                                                                             %
2003 %                                                                             %
2004 %                                                                             %
2005 +   G e t I m a g e P i x e l C a c h e                                       %
2006 %                                                                             %
2007 %                                                                             %
2008 %                                                                             %
2009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2010 %
2011 %  GetImagePixelCache() ensures that there is only a single reference to the
2012 %  pixel cache to be modified, updating the provided cache pointer to point to
2013 %  a clone of the original pixel cache if necessary.
2014 %
2015 %  The format of the GetImagePixelCache method is:
2016 %
2017 %      Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2018 %        ExceptionInfo *exception)
2019 %
2020 %  A description of each parameter follows:
2021 %
2022 %    o image: the image.
2023 %
2024 %    o clone: any value other than MagickFalse clones the cache pixels.
2025 %
2026 %    o exception: return any errors or warnings in this structure.
2027 %
2028 */
2029 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2030 {
2031   CacheInfo
2032     *cache_info;
2033
2034   /*
2035     Does the image match the pixel cache morphology?
2036   */
2037   cache_info=(CacheInfo *) image->cache;
2038   if ((image->storage_class != cache_info->storage_class) ||
2039       (image->colorspace != cache_info->colorspace) ||
2040       (image->columns != cache_info->columns) ||
2041       (image->rows != cache_info->rows) ||
2042       (cache_info->nexus_info == (NexusInfo **) NULL) ||
2043       (cache_info->number_threads < GetOpenMPMaximumThreads()))
2044     return(MagickFalse);
2045   return(MagickTrue);
2046 }
2047
2048 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2049   ExceptionInfo *exception)
2050 {
2051   CacheInfo
2052     *cache_info;
2053
2054   MagickBooleanType
2055     destroy,
2056     status;
2057
2058   static MagickSizeType
2059     cpu_throttle = 0,
2060     cycles = 0,
2061     time_limit = 0;
2062
2063   static time_t
2064     cache_genesis = 0;
2065
2066   status=MagickTrue;
2067   LockSemaphoreInfo(image->semaphore);
2068   if (cpu_throttle == 0)
2069     {
2070       char
2071         *limit;
2072
2073       /*
2074         Set CPU throttle in milleseconds.
2075       */
2076       cpu_throttle=MagickResourceInfinity;
2077       limit=GetEnvironmentValue("MAGICK_THROTTLE");
2078       if (limit == (char *) NULL)
2079         limit=GetPolicyValue("throttle");
2080       if (limit != (char *) NULL)
2081         {
2082           cpu_throttle=(MagickSizeType) StringToInteger(limit);
2083           limit=DestroyString(limit);
2084         }
2085     }
2086   if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2087     MagickDelay(cpu_throttle);
2088   if (time_limit == 0)
2089     {
2090       /*
2091         Set the exire time in seconds.
2092       */
2093       time_limit=GetMagickResourceLimit(TimeResource);
2094       cache_genesis=time((time_t *) NULL);
2095     }
2096   if ((time_limit != MagickResourceInfinity) &&
2097       ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
2098     ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2099   assert(image->cache != (Cache) NULL);
2100   cache_info=(CacheInfo *) image->cache;
2101   destroy=MagickFalse;
2102   if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2103     {
2104       LockSemaphoreInfo(cache_info->semaphore);
2105       if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2106         {
2107           Image
2108             clone_image;
2109
2110           CacheInfo
2111             *clone_info;
2112
2113           /*
2114             Clone pixel cache.
2115           */
2116           clone_image=(*image);
2117           clone_image.semaphore=AllocateSemaphoreInfo();
2118           clone_image.reference_count=1;
2119           clone_image.cache=ClonePixelCache(cache_info);
2120           clone_info=(CacheInfo *) clone_image.cache;
2121           status=OpenPixelCache(&clone_image,IOMode,exception);
2122           if (status != MagickFalse)
2123             {
2124               if (clone != MagickFalse)
2125                 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2126               if (status != MagickFalse)
2127                 {
2128                   destroy=MagickTrue;
2129                   image->cache=clone_image.cache;
2130                 }
2131             }
2132           DestroySemaphoreInfo(&clone_image.semaphore);
2133         }
2134       UnlockSemaphoreInfo(cache_info->semaphore);
2135     }
2136   if (destroy != MagickFalse)
2137     cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2138   if (status != MagickFalse)
2139     {
2140       /*
2141         Ensure the image matches the pixel cache morphology.
2142       */
2143       image->taint=MagickTrue;
2144       image->type=UndefinedType;
2145       if (image->colorspace == GRAYColorspace)
2146         image->colorspace=RGBColorspace;
2147       if (ValidatePixelCacheMorphology(image) == MagickFalse)
2148         status=OpenPixelCache(image,IOMode,exception);
2149     }
2150   UnlockSemaphoreInfo(image->semaphore);
2151   if (status == MagickFalse)
2152     return((Cache) NULL);
2153   return(image->cache);
2154 }
2155 \f
2156 /*
2157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2158 %                                                                             %
2159 %                                                                             %
2160 %                                                                             %
2161 %   G e t O n e A u t h e n t i c P i x e l                                   %
2162 %                                                                             %
2163 %                                                                             %
2164 %                                                                             %
2165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166 %
2167 %  GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2168 %  location.  The image background color is returned if an error occurs.
2169 %
2170 %  The format of the GetOneAuthenticPixel() method is:
2171 %
2172 %      MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2173 %        const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2174 %
2175 %  A description of each parameter follows:
2176 %
2177 %    o image: the image.
2178 %
2179 %    o x,y:  These values define the location of the pixel to return.
2180 %
2181 %    o pixel: return a pixel at the specified (x,y) location.
2182 %
2183 %    o exception: return any errors or warnings in this structure.
2184 %
2185 */
2186 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2187   const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2188 {
2189   CacheInfo
2190     *cache_info;
2191
2192   PixelPacket
2193     *pixels;
2194
2195   assert(image != (Image *) NULL);
2196   assert(image->signature == MagickSignature);
2197   assert(image->cache != (Cache) NULL);
2198   cache_info=(CacheInfo *) image->cache;
2199   assert(cache_info->signature == MagickSignature);
2200   *pixel=image->background_color;
2201   if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2202        (GetOneAuthenticPixelFromHandler) NULL)
2203     return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2204       pixel,exception));
2205   *pixel=image->background_color;
2206   pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2207   if (pixels == (PixelPacket *) NULL)
2208     return(MagickFalse);
2209   *pixel=(*pixels);
2210   return(MagickTrue);
2211 }
2212 \f
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,
2230 %        const ssize_t x,const ssize_t y,PixelPacket *pixel,
2231 %        ExceptionInfo *exception)
2232 %
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 */
2244 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2245   const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2246 {
2247   CacheInfo
2248     *cache_info;
2249
2250   const int
2251     id = GetOpenMPThreadId();
2252
2253   PixelPacket
2254     *pixels;
2255
2256   assert(image != (const Image *) NULL);
2257   assert(image->signature == MagickSignature);
2258   assert(image->cache != (Cache) NULL);
2259   cache_info=(CacheInfo *) image->cache;
2260   assert(cache_info->signature == MagickSignature);
2261   *pixel=image->background_color;
2262   assert(id < (int) cache_info->number_threads);
2263   pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2264     cache_info->nexus_info[id],exception);
2265   if (pixels == (PixelPacket *) NULL)
2266     return(MagickFalse);
2267   *pixel=(*pixels);
2268   return(MagickTrue);
2269 }
2270 \f
2271 /*
2272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2273 %                                                                             %
2274 %                                                                             %
2275 %                                                                             %
2276 %   G e t O n e V i r t u a l M a g i c k P i x e l                           %
2277 %                                                                             %
2278 %                                                                             %
2279 %                                                                             %
2280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2281 %
2282 %  GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2283 %  location.  The image background color is returned if an error occurs.  If
2284 %  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2285 %
2286 %  The format of the GetOneVirtualMagickPixel() method is:
2287 %
2288 %      MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2289 %        const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2290 %        ExceptionInfo exception)
2291 %
2292 %  A description of each parameter follows:
2293 %
2294 %    o image: the image.
2295 %
2296 %    o x,y:  these values define the location of the pixel to return.
2297 %
2298 %    o pixel: return a pixel at the specified (x,y) location.
2299 %
2300 %    o exception: return any errors or warnings in this structure.
2301 %
2302 */
2303 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2304   const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2305   ExceptionInfo *exception)
2306 {
2307   CacheInfo
2308     *cache_info;
2309
2310   const int
2311     id = GetOpenMPThreadId();
2312
2313   register const IndexPacket
2314     *indexes;
2315
2316   register const PixelPacket
2317     *pixels;
2318
2319   assert(image != (const Image *) NULL);
2320   assert(image->signature == MagickSignature);
2321   assert(image->cache != (Cache) NULL);
2322   cache_info=(CacheInfo *) image->cache;
2323   assert(cache_info->signature == MagickSignature);
2324   assert(id < (int) cache_info->number_threads);
2325   pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2326     1UL,1UL,cache_info->nexus_info[id],exception);
2327   GetMagickPixelPacket(image,pixel);
2328   if (pixels == (const PixelPacket *) NULL)
2329     return(MagickFalse);
2330   indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
2331   SetMagickPixelPacket(image,pixels,indexes,pixel);
2332   return(MagickTrue);
2333 }
2334 \f
2335 /*
2336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337 %                                                                             %
2338 %                                                                             %
2339 %                                                                             %
2340 %   G e t O n e V i r t u a l M e t h o d P i x e l                           %
2341 %                                                                             %
2342 %                                                                             %
2343 %                                                                             %
2344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2345 %
2346 %  GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2347 %  location as defined by specified pixel method.  The image background color
2348 %  is returned if an error occurs.  If you plan to modify the pixel, use
2349 %  GetOneAuthenticPixel() instead.
2350 %
2351 %  The format of the GetOneVirtualMethodPixel() method is:
2352 %
2353 %      MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2354 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2355 %        const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
2356 %
2357 %  A description of each parameter follows:
2358 %
2359 %    o image: the image.
2360 %
2361 %    o virtual_pixel_method: the virtual pixel method.
2362 %
2363 %    o x,y:  These values define the location of the pixel to return.
2364 %
2365 %    o pixel: return a pixel at the specified (x,y) location.
2366 %
2367 %    o exception: return any errors or warnings in this structure.
2368 %
2369 */
2370 MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2371   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2372   PixelPacket *pixel,ExceptionInfo *exception)
2373 {
2374   CacheInfo
2375     *cache_info;
2376
2377   const int
2378     id = GetOpenMPThreadId();
2379
2380   const PixelPacket
2381     *pixels;
2382
2383   assert(image != (const Image *) NULL);
2384   assert(image->signature == MagickSignature);
2385   assert(image->cache != (Cache) NULL);
2386   cache_info=(CacheInfo *) image->cache;
2387   assert(cache_info->signature == MagickSignature);
2388   *pixel=image->background_color;
2389   if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2390        (GetOneVirtualPixelFromHandler) NULL)
2391     return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2392       virtual_pixel_method,x,y,pixel,exception));
2393   assert(id < (int) cache_info->number_threads);
2394   pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2395     cache_info->nexus_info[id],exception);
2396   if (pixels == (const PixelPacket *) NULL)
2397     return(MagickFalse);
2398   *pixel=(*pixels);
2399   return(MagickTrue);
2400 }
2401 \f
2402 /*
2403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2404 %                                                                             %
2405 %                                                                             %
2406 %                                                                             %
2407 %   G e t O n e V i r t u a l P i x e l                                       %
2408 %                                                                             %
2409 %                                                                             %
2410 %                                                                             %
2411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2412 %
2413 %  GetOneVirtualPixel() returns a single virtual pixel at the specified
2414 %  (x,y) location.  The image background color is returned if an error occurs.
2415 %  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2416 %
2417 %  The format of the GetOneVirtualPixel() method is:
2418 %
2419 %      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2420 %        const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
2421 %
2422 %  A description of each parameter follows:
2423 %
2424 %    o image: the image.
2425 %
2426 %    o x,y:  These values define the location of the pixel to return.
2427 %
2428 %    o pixel: return a pixel at the specified (x,y) location.
2429 %
2430 %    o exception: return any errors or warnings in this structure.
2431 %
2432 */
2433 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2434   const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2435 {
2436   CacheInfo
2437     *cache_info;
2438
2439   const int
2440     id = GetOpenMPThreadId();
2441
2442   const PixelPacket
2443     *pixels;
2444
2445   assert(image != (const Image *) NULL);
2446   assert(image->signature == MagickSignature);
2447   assert(image->cache != (Cache) NULL);
2448   cache_info=(CacheInfo *) image->cache;
2449   assert(cache_info->signature == MagickSignature);
2450   *pixel=image->background_color;
2451   if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2452        (GetOneVirtualPixelFromHandler) NULL)
2453     return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2454       GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2455   assert(id < (int) cache_info->number_threads);
2456   pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2457     1UL,1UL,cache_info->nexus_info[id],exception);
2458   if (pixels == (const PixelPacket *) NULL)
2459     return(MagickFalse);
2460   *pixel=(*pixels);
2461   return(MagickTrue);
2462 }
2463 \f
2464 /*
2465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466 %                                                                             %
2467 %                                                                             %
2468 %                                                                             %
2469 +   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                     %
2470 %                                                                             %
2471 %                                                                             %
2472 %                                                                             %
2473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2474 %
2475 %  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2476 %  specified (x,y) location.  The image background color is returned if an
2477 %  error occurs.
2478 %
2479 %  The format of the GetOneVirtualPixelFromCache() method is:
2480 %
2481 %      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2482 %        const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
2483 %        PixelPacket *pixel,ExceptionInfo *exception)
2484 %
2485 %  A description of each parameter follows:
2486 %
2487 %    o image: the image.
2488 %
2489 %    o virtual_pixel_method: the virtual pixel method.
2490 %
2491 %    o x,y:  These values define the location of the pixel to return.
2492 %
2493 %    o pixel: return a pixel at the specified (x,y) location.
2494 %
2495 %    o exception: return any errors or warnings in this structure.
2496 %
2497 */
2498 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2499   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2500   PixelPacket *pixel,ExceptionInfo *exception)
2501 {
2502   CacheInfo
2503     *cache_info;
2504
2505   const int
2506     id = GetOpenMPThreadId();
2507
2508   const PixelPacket
2509     *pixels;
2510
2511   assert(image != (const Image *) NULL);
2512   assert(image->signature == MagickSignature);
2513   assert(image->cache != (Cache) NULL);
2514   cache_info=(CacheInfo *) image->cache;
2515   assert(cache_info->signature == MagickSignature);
2516   assert(id < (int) cache_info->number_threads);
2517   *pixel=image->background_color;
2518   pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2519     cache_info->nexus_info[id],exception);
2520   if (pixels == (const PixelPacket *) NULL)
2521     return(MagickFalse);
2522   *pixel=(*pixels);
2523   return(MagickTrue);
2524 }
2525 \f
2526 /*
2527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2528 %                                                                             %
2529 %                                                                             %
2530 %                                                                             %
2531 +   G e t P i x e l C a c h e C o l o r s p a c e                             %
2532 %                                                                             %
2533 %                                                                             %
2534 %                                                                             %
2535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2536 %
2537 %  GetPixelCacheColorspace() returns the class type of the pixel cache.
2538 %
2539 %  The format of the GetPixelCacheColorspace() method is:
2540 %
2541 %      Colorspace GetPixelCacheColorspace(Cache cache)
2542 %
2543 %  A description of each parameter follows:
2544 %
2545 %    o cache: the pixel cache.
2546 %
2547 */
2548 MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2549 {
2550   CacheInfo
2551     *cache_info;
2552
2553   assert(cache != (Cache) NULL);
2554   cache_info=(CacheInfo *) cache;
2555   assert(cache_info->signature == MagickSignature);
2556   if (cache_info->debug != MagickFalse)
2557     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2558       cache_info->filename);
2559   return(cache_info->colorspace);
2560 }
2561 \f
2562 /*
2563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2564 %                                                                             %
2565 %                                                                             %
2566 %                                                                             %
2567 +   G e t P i x e l C a c h e M e t h o d s                                   %
2568 %                                                                             %
2569 %                                                                             %
2570 %                                                                             %
2571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2572 %
2573 %  GetPixelCacheMethods() initializes the CacheMethods structure.
2574 %
2575 %  The format of the GetPixelCacheMethods() method is:
2576 %
2577 %      void GetPixelCacheMethods(CacheMethods *cache_methods)
2578 %
2579 %  A description of each parameter follows:
2580 %
2581 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
2582 %
2583 */
2584 MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2585 {
2586   assert(cache_methods != (CacheMethods *) NULL);
2587   (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2588   cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2589   cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2590   cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2591   cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2592   cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2593   cache_methods->get_authentic_indexes_from_handler=
2594     GetAuthenticIndexesFromCache;
2595   cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2596   cache_methods->get_one_authentic_pixel_from_handler=
2597     GetOneAuthenticPixelFromCache;
2598   cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2599   cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2600   cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2601 }
2602 \f
2603 /*
2604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2605 %                                                                             %
2606 %                                                                             %
2607 %                                                                             %
2608 +   G e t P i x e l C a c h e N e x u s E x t e n t                           %
2609 %                                                                             %
2610 %                                                                             %
2611 %                                                                             %
2612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2613 %
2614 %  GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2615 %  the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2616 %
2617 %  The format of the GetPixelCacheNexusExtent() method is:
2618 %
2619 %      MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2620 %        NexusInfo *nexus_info)
2621 %
2622 %  A description of each parameter follows:
2623 %
2624 %    o nexus_info: the nexus info.
2625 %
2626 */
2627 MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2628   NexusInfo *nexus_info)
2629 {
2630   CacheInfo
2631     *cache_info;
2632
2633   MagickSizeType
2634     extent;
2635
2636   assert(cache != (const Cache) NULL);
2637   cache_info=(CacheInfo *) cache;
2638   assert(cache_info->signature == MagickSignature);
2639   extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2640   if (extent == 0)
2641     return((MagickSizeType) cache_info->columns*cache_info->rows);
2642   return(extent);
2643 }
2644 \f
2645 /*
2646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2647 %                                                                             %
2648 %                                                                             %
2649 %                                                                             %
2650 +   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                         %
2651 %                                                                             %
2652 %                                                                             %
2653 %                                                                             %
2654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2655 %
2656 %  GetPixelCacheNexusIndexes() returns the indexes associated with the
2657 %  specified cache nexus.
2658 %
2659 %  The format of the GetPixelCacheNexusIndexes() method is:
2660 %
2661 %      IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2662 %        NexusInfo *nexus_info)
2663 %
2664 %  A description of each parameter follows:
2665 %
2666 %    o cache: the pixel cache.
2667 %
2668 %    o nexus_info: the cache nexus to return the colormap indexes.
2669 %
2670 */
2671 MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2672   NexusInfo *nexus_info)
2673 {
2674   CacheInfo
2675     *cache_info;
2676
2677   assert(cache != (const Cache) NULL);
2678   cache_info=(CacheInfo *) cache;
2679   assert(cache_info->signature == MagickSignature);
2680   if (cache_info->storage_class == UndefinedClass)
2681     return((IndexPacket *) NULL);
2682   return(nexus_info->indexes);
2683 }
2684 \f
2685 /*
2686 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2687 %                                                                             %
2688 %                                                                             %
2689 %                                                                             %
2690 +   G e t P i x e l C a c h e N e x u s P i x e l s                           %
2691 %                                                                             %
2692 %                                                                             %
2693 %                                                                             %
2694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2695 %
2696 %  GetPixelCacheNexusPixels() returns the pixels associated with the specified
2697 %  cache nexus.
2698 %
2699 %  The format of the GetPixelCacheNexusPixels() method is:
2700 %
2701 %      PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2702 %        NexusInfo *nexus_info)
2703 %
2704 %  A description of each parameter follows:
2705 %
2706 %    o cache: the pixel cache.
2707 %
2708 %    o nexus_info: the cache nexus to return the pixels.
2709 %
2710 */
2711 MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2712   NexusInfo *nexus_info)
2713 {
2714   CacheInfo
2715     *cache_info;
2716
2717   assert(cache != (const Cache) NULL);
2718   cache_info=(CacheInfo *) cache;
2719   assert(cache_info->signature == MagickSignature);
2720   if (cache_info->storage_class == UndefinedClass)
2721     return((PixelPacket *) NULL);
2722   return(nexus_info->pixels);
2723 }
2724 \f
2725 /*
2726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2727 %                                                                             %
2728 %                                                                             %
2729 %                                                                             %
2730 +   G e t P i x e l C a c h e P i x e l s                                     %
2731 %                                                                             %
2732 %                                                                             %
2733 %                                                                             %
2734 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2735 %
2736 %  GetPixelCachePixels() returns the pixels associated with the specified image.
2737 %
2738 %  The format of the GetPixelCachePixels() method is:
2739 %
2740 %      void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2741 %        ExceptionInfo *exception)
2742 %
2743 %  A description of each parameter follows:
2744 %
2745 %    o image: the image.
2746 %
2747 %    o length: the pixel cache length.
2748 %
2749 %    o exception: return any errors or warnings in this structure.
2750 %
2751 */
2752 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2753   ExceptionInfo *exception)
2754 {
2755   CacheInfo
2756     *cache_info;
2757
2758   assert(image != (const Image *) NULL);
2759   assert(image->signature == MagickSignature);
2760   assert(image->cache != (Cache) NULL);
2761   cache_info=(CacheInfo *) image->cache;
2762   assert(cache_info->signature == MagickSignature);
2763   *length=0;
2764   if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2765     return((void *) NULL);
2766   *length=cache_info->length;
2767   return((void *) cache_info->pixels);
2768 }
2769 \f
2770 /*
2771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2772 %                                                                             %
2773 %                                                                             %
2774 %                                                                             %
2775 +   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                         %
2776 %                                                                             %
2777 %                                                                             %
2778 %                                                                             %
2779 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2780 %
2781 %  GetPixelCacheStorageClass() returns the class type of the pixel cache.
2782 %
2783 %  The format of the GetPixelCacheStorageClass() method is:
2784 %
2785 %      ClassType GetPixelCacheStorageClass(Cache cache)
2786 %
2787 %  A description of each parameter follows:
2788 %
2789 %    o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2790 %
2791 %    o cache: the pixel cache.
2792 %
2793 */
2794 MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2795 {
2796   CacheInfo
2797     *cache_info;
2798
2799   assert(cache != (Cache) NULL);
2800   cache_info=(CacheInfo *) cache;
2801   assert(cache_info->signature == MagickSignature);
2802   if (cache_info->debug != MagickFalse)
2803     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2804       cache_info->filename);
2805   return(cache_info->storage_class);
2806 }
2807 \f
2808 /*
2809 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2810 %                                                                             %
2811 %                                                                             %
2812 %                                                                             %
2813 +   G e t P i x e l C a c h e T i l e S i z e                                 %
2814 %                                                                             %
2815 %                                                                             %
2816 %                                                                             %
2817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2818 %
2819 %  GetPixelCacheTileSize() returns the pixel cache tile size.
2820 %
2821 %  The format of the GetPixelCacheTileSize() method is:
2822 %
2823 %      void GetPixelCacheTileSize(const Image *image,size_t *width,
2824 %        size_t *height)
2825 %
2826 %  A description of each parameter follows:
2827 %
2828 %    o image: the image.
2829 %
2830 %    o width: the optimize cache tile width in pixels.
2831 %
2832 %    o height: the optimize cache tile height in pixels.
2833 %
2834 */
2835 MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2836   size_t *height)
2837 {
2838   assert(image != (Image *) NULL);
2839   assert(image->signature == MagickSignature);
2840   if (image->debug != MagickFalse)
2841     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2842   *width=2048UL/sizeof(PixelPacket);
2843   if (GetPixelCacheType(image) == DiskCache)
2844     *width=8192UL/sizeof(PixelPacket);
2845   *height=(*width);
2846 }
2847 \f
2848 /*
2849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2850 %                                                                             %
2851 %                                                                             %
2852 %                                                                             %
2853 +   G e t P i x e l C a c h e T y p e                                         %
2854 %                                                                             %
2855 %                                                                             %
2856 %                                                                             %
2857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2858 %
2859 %  GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2860 %
2861 %  The format of the GetPixelCacheType() method is:
2862 %
2863 %      CacheType GetPixelCacheType(const Image *image)
2864 %
2865 %  A description of each parameter follows:
2866 %
2867 %    o image: the image.
2868 %
2869 */
2870 MagickExport CacheType GetPixelCacheType(const Image *image)
2871 {
2872   CacheInfo
2873     *cache_info;
2874
2875   assert(image != (Image *) NULL);
2876   assert(image->signature == MagickSignature);
2877   assert(image->cache != (Cache) NULL);
2878   cache_info=(CacheInfo *) image->cache;
2879   assert(cache_info->signature == MagickSignature);
2880   return(cache_info->type);
2881 }
2882 \f
2883 /*
2884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885 %                                                                             %
2886 %                                                                             %
2887 %                                                                             %
2888 +   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                       %
2889 %                                                                             %
2890 %                                                                             %
2891 %                                                                             %
2892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2893 %
2894 %  GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2895 %  pixel cache.  A virtual pixel is any pixel access that is outside the
2896 %  boundaries of the image cache.
2897 %
2898 %  The format of the GetPixelCacheVirtualMethod() method is:
2899 %
2900 %      VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2901 %
2902 %  A description of each parameter follows:
2903 %
2904 %    o image: the image.
2905 %
2906 */
2907 MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2908 {
2909   CacheInfo
2910     *cache_info;
2911
2912   assert(image != (Image *) NULL);
2913   assert(image->signature == MagickSignature);
2914   assert(image->cache != (Cache) NULL);
2915   cache_info=(CacheInfo *) image->cache;
2916   assert(cache_info->signature == MagickSignature);
2917   return(cache_info->virtual_pixel_method);
2918 }
2919 \f
2920 /*
2921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2922 %                                                                             %
2923 %                                                                             %
2924 %                                                                             %
2925 +   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                       %
2926 %                                                                             %
2927 %                                                                             %
2928 %                                                                             %
2929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2930 %
2931 %  GetVirtualIndexesFromCache() returns the indexes associated with the last
2932 %  call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2933 %
2934 %  The format of the GetVirtualIndexesFromCache() method is:
2935 %
2936 %      IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2937 %
2938 %  A description of each parameter follows:
2939 %
2940 %    o image: the image.
2941 %
2942 */
2943 static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2944 {
2945   CacheInfo
2946     *cache_info;
2947
2948   const int
2949     id = GetOpenMPThreadId();
2950
2951   assert(image != (const Image *) NULL);
2952   assert(image->signature == MagickSignature);
2953   assert(image->cache != (Cache) NULL);
2954   cache_info=(CacheInfo *) image->cache;
2955   assert(cache_info->signature == MagickSignature);
2956   assert(id < (int) cache_info->number_threads);
2957   return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
2958 }
2959 \f
2960 /*
2961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2962 %                                                                             %
2963 %                                                                             %
2964 %                                                                             %
2965 +   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                       %
2966 %                                                                             %
2967 %                                                                             %
2968 %                                                                             %
2969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2970 %
2971 %  GetVirtualIndexesFromNexus() returns the indexes associated with the
2972 %  specified cache nexus.
2973 %
2974 %  The format of the GetVirtualIndexesFromNexus() method is:
2975 %
2976 %      const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2977 %        NexusInfo *nexus_info)
2978 %
2979 %  A description of each parameter follows:
2980 %
2981 %    o cache: the pixel cache.
2982 %
2983 %    o nexus_info: the cache nexus to return the colormap indexes.
2984 %
2985 */
2986 MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2987   NexusInfo *nexus_info)
2988 {
2989   CacheInfo
2990     *cache_info;
2991
2992   assert(cache != (Cache) NULL);
2993   cache_info=(CacheInfo *) cache;
2994   assert(cache_info->signature == MagickSignature);
2995   if (cache_info->storage_class == UndefinedClass)
2996     return((IndexPacket *) NULL);
2997   return(nexus_info->indexes);
2998 }
2999 \f
3000 /*
3001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3002 %                                                                             %
3003 %                                                                             %
3004 %                                                                             %
3005 %   G e t V i r t u a l I n d e x Q u e u e                                   %
3006 %                                                                             %
3007 %                                                                             %
3008 %                                                                             %
3009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3010 %
3011 %  GetVirtualIndexQueue() returns the virtual black channel or the
3012 %  colormap indexes associated with the last call to QueueAuthenticPixels() or
3013 %  GetVirtualPixels().  NULL is returned if the black channel or colormap
3014 %  indexes are not available.
3015 %
3016 %  The format of the GetVirtualIndexQueue() method is:
3017 %
3018 %      const IndexPacket *GetVirtualIndexQueue(const Image *image)
3019 %
3020 %  A description of each parameter follows:
3021 %
3022 %    o image: the image.
3023 %
3024 */
3025 MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3026 {
3027   CacheInfo
3028     *cache_info;
3029
3030   const int
3031     id = GetOpenMPThreadId();
3032
3033   assert(image != (const Image *) NULL);
3034   assert(image->signature == MagickSignature);
3035   assert(image->cache != (Cache) NULL);
3036   cache_info=(CacheInfo *) image->cache;
3037   assert(cache_info->signature == MagickSignature);
3038   if (cache_info->methods.get_virtual_indexes_from_handler !=
3039        (GetVirtualIndexesFromHandler) NULL)
3040     return(cache_info->methods.get_virtual_indexes_from_handler(image));
3041   assert(id < (int) cache_info->number_threads);
3042   return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
3043 }
3044 \f
3045 /*
3046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3047 %                                                                             %
3048 %                                                                             %
3049 %                                                                             %
3050 +   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                         %
3051 %                                                                             %
3052 %                                                                             %
3053 %                                                                             %
3054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3055 %
3056 %  GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3057 %  pixel cache as defined by the geometry parameters.   A pointer to the pixels
3058 %  is returned if the pixels are transferred, otherwise a NULL is returned.
3059 %
3060 %  The format of the GetVirtualPixelsFromNexus() method is:
3061 %
3062 %      PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3063 %        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3064 %        const size_t columns,const size_t rows,NexusInfo *nexus_info,
3065 %        ExceptionInfo *exception)
3066 %
3067 %  A description of each parameter follows:
3068 %
3069 %    o image: the image.
3070 %
3071 %    o virtual_pixel_method: the virtual pixel method.
3072 %
3073 %    o x,y,columns,rows:  These values define the perimeter of a region of
3074 %      pixels.
3075 %
3076 %    o nexus_info: the cache nexus to acquire.
3077 %
3078 %    o exception: return any errors or warnings in this structure.
3079 %
3080 */
3081
3082 static ssize_t
3083   DitherMatrix[64] =
3084   {
3085      0,  48,  12,  60,   3,  51,  15,  63,
3086     32,  16,  44,  28,  35,  19,  47,  31,
3087      8,  56,   4,  52,  11,  59,   7,  55,
3088     40,  24,  36,  20,  43,  27,  39,  23,
3089      2,  50,  14,  62,   1,  49,  13,  61,
3090     34,  18,  46,  30,  33,  17,  45,  29,
3091     10,  58,   6,  54,   9,  57,   5,  53,
3092     42,  26,  38,  22,  41,  25,  37,  21
3093   };
3094
3095 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3096 {
3097   ssize_t
3098     index;
3099
3100   index=x+DitherMatrix[x & 0x07]-32L;
3101   if (index < 0L)
3102     return(0L);
3103   if (index >= (ssize_t) columns)
3104     return((ssize_t) columns-1L);
3105   return(index);
3106 }
3107
3108 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3109 {
3110   ssize_t
3111     index;
3112
3113   index=y+DitherMatrix[y & 0x07]-32L;
3114   if (index < 0L)
3115     return(0L);
3116   if (index >= (ssize_t) rows)
3117     return((ssize_t) rows-1L);
3118   return(index);
3119 }
3120
3121 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3122 {
3123   if (x < 0L)
3124     return(0L);
3125   if (x >= (ssize_t) columns)
3126     return((ssize_t) (columns-1));
3127   return(x);
3128 }
3129
3130 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3131 {
3132   if (y < 0L)
3133     return(0L);
3134   if (y >= (ssize_t) rows)
3135     return((ssize_t) (rows-1));
3136   return(y);
3137 }
3138
3139 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3140 {
3141   return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3142 }
3143
3144 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3145 {
3146   return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3147 }
3148
3149 /*
3150   VirtualPixelModulo() computes the remainder of dividing offset by extent.  It
3151   returns not only the quotient (tile the offset falls in) but also the positive
3152   remainer within that tile such that 0 <= remainder < extent.  This method is
3153   essentially a ldiv() using a floored modulo division rather than the normal
3154   default truncated modulo division.
3155 */
3156 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3157   const size_t extent)
3158 {
3159   MagickModulo
3160     modulo;
3161
3162   modulo.quotient=offset/(ssize_t) extent;
3163   if (offset < 0L)
3164     modulo.quotient--;
3165   modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3166   return(modulo);
3167 }
3168
3169 MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3170   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3171   const size_t columns,const size_t rows,NexusInfo *nexus_info,
3172   ExceptionInfo *exception)
3173 {
3174   CacheInfo
3175     *cache_info;
3176
3177   IndexPacket
3178     virtual_index;
3179
3180   MagickOffsetType
3181     offset;
3182
3183   MagickSizeType
3184     length,
3185     number_pixels;
3186
3187   NexusInfo
3188     **virtual_nexus;
3189
3190   PixelPacket
3191     *pixels,
3192     virtual_pixel;
3193
3194   RectangleInfo
3195     region;
3196
3197   register const IndexPacket
3198     *restrict virtual_indexes;
3199
3200   register const PixelPacket
3201     *restrict p;
3202
3203   register IndexPacket
3204     *restrict indexes;
3205
3206   register PixelPacket
3207     *restrict q;
3208
3209   register ssize_t
3210     u,
3211     v;
3212
3213   /*
3214     Acquire pixels.
3215   */
3216   assert(image != (const Image *) NULL);
3217   assert(image->signature == MagickSignature);
3218   assert(image->cache != (Cache) NULL);
3219   cache_info=(CacheInfo *) image->cache;
3220   assert(cache_info->signature == MagickSignature);
3221   if (cache_info->type == UndefinedCache)
3222     return((const PixelPacket *) NULL);
3223   region.x=x;
3224   region.y=y;
3225   region.width=columns;
3226   region.height=rows;
3227   pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3228   if (pixels == (PixelPacket *) NULL)
3229     return((const PixelPacket *) NULL);
3230   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3231     nexus_info->region.x;
3232   length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3233     nexus_info->region.width-1L;
3234   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3235   if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3236     if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3237         (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3238       {
3239         MagickBooleanType
3240           status;
3241
3242         /*
3243           Pixel request is inside cache extents.
3244         */
3245         if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3246           return(pixels);
3247         status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3248         if (status == MagickFalse)
3249           return((const PixelPacket *) NULL);
3250         if ((cache_info->storage_class == PseudoClass) ||
3251             (cache_info->colorspace == CMYKColorspace))
3252           {
3253             status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3254             if (status == MagickFalse)
3255               return((const PixelPacket *) NULL);
3256           }
3257         return(pixels);
3258       }
3259   /*
3260     Pixel request is outside cache extents.
3261   */
3262   q=pixels;
3263   indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3264   virtual_nexus=AcquirePixelCacheNexus(1);
3265   if (virtual_nexus == (NexusInfo **) NULL)
3266     {
3267       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3268         "UnableToGetCacheNexus","`%s'",image->filename);
3269       return((const PixelPacket *) NULL);
3270     }
3271   switch (virtual_pixel_method)
3272   {
3273     case BlackVirtualPixelMethod:
3274     {
3275       SetRedPixelComponent(&virtual_pixel,0);
3276       SetGreenPixelComponent(&virtual_pixel,0);
3277       SetBluePixelComponent(&virtual_pixel,0);
3278       SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3279       break;
3280     }
3281     case GrayVirtualPixelMethod:
3282     {
3283       SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3284       SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3285       SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3286       SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3287       break;
3288     }
3289     case TransparentVirtualPixelMethod:
3290     {
3291       SetRedPixelComponent(&virtual_pixel,0);
3292       SetGreenPixelComponent(&virtual_pixel,0);
3293       SetBluePixelComponent(&virtual_pixel,0);
3294       SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
3295       break;
3296     }
3297     case MaskVirtualPixelMethod:
3298     case WhiteVirtualPixelMethod:
3299     {
3300       SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3301       SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3302       SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3303       SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3304       break;
3305     }
3306     default:
3307     {
3308       virtual_pixel=image->background_color;
3309       break;
3310     }
3311   }
3312   virtual_index=0;
3313   for (v=0; v < (ssize_t) rows; v++)
3314   {
3315     for (u=0; u < (ssize_t) columns; u+=length)
3316     {
3317       length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3318       if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3319           (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3320           (length == 0))
3321         {
3322           MagickModulo
3323             x_modulo,
3324             y_modulo;
3325
3326           /*
3327             Transfer a single pixel.
3328           */
3329           length=(MagickSizeType) 1;
3330           switch (virtual_pixel_method)
3331           {
3332             case BackgroundVirtualPixelMethod:
3333             case ConstantVirtualPixelMethod:
3334             case BlackVirtualPixelMethod:
3335             case GrayVirtualPixelMethod:
3336             case TransparentVirtualPixelMethod:
3337             case MaskVirtualPixelMethod:
3338             case WhiteVirtualPixelMethod:
3339             {
3340               p=(&virtual_pixel);
3341               virtual_indexes=(&virtual_index);
3342               break;
3343             }
3344             case EdgeVirtualPixelMethod:
3345             default:
3346             {
3347               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3348                 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3349                 1UL,1UL,*virtual_nexus,exception);
3350               virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3351                 *virtual_nexus);
3352               break;
3353             }
3354             case RandomVirtualPixelMethod:
3355             {
3356               if (cache_info->random_info == (RandomInfo *) NULL)
3357                 cache_info->random_info=AcquireRandomInfo();
3358               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3359                 RandomX(cache_info->random_info,cache_info->columns),
3360                 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3361                 *virtual_nexus,exception);
3362               virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3363                 *virtual_nexus);
3364               break;
3365             }
3366             case DitherVirtualPixelMethod:
3367             {
3368               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3369                 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3370                 1UL,1UL,*virtual_nexus,exception);
3371               virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3372                 *virtual_nexus);
3373               break;
3374             }
3375             case TileVirtualPixelMethod:
3376             {
3377               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3378               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3379               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3380                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3381                 exception);
3382               virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3383                 *virtual_nexus);
3384               break;
3385             }
3386             case MirrorVirtualPixelMethod:
3387             {
3388               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3389               if ((x_modulo.quotient & 0x01) == 1L)
3390                 x_modulo.remainder=(ssize_t) cache_info->columns-
3391                   x_modulo.remainder-1L;
3392               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3393               if ((y_modulo.quotient & 0x01) == 1L)
3394                 y_modulo.remainder=(ssize_t) cache_info->rows-
3395                   y_modulo.remainder-1L;
3396               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3397                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3398                 exception);
3399               virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3400                 *virtual_nexus);
3401               break;
3402             }
3403             case CheckerTileVirtualPixelMethod:
3404             {
3405               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3406               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3407               if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3408                 {
3409                   p=(&virtual_pixel);
3410                   virtual_indexes=(&virtual_index);
3411                   break;
3412                 }
3413               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3414                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3415                 exception);
3416               virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3417                 *virtual_nexus);
3418               break;
3419             }
3420             case HorizontalTileVirtualPixelMethod:
3421             {
3422               if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3423                 {
3424                   p=(&virtual_pixel);
3425                   virtual_indexes=(&virtual_index);
3426                   break;
3427                 }
3428               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3429               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3430               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3431                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3432                 exception);
3433               virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3434                 *virtual_nexus);
3435               break;
3436             }
3437             case VerticalTileVirtualPixelMethod:
3438             {
3439               if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3440                 {
3441                   p=(&virtual_pixel);
3442                   virtual_indexes=(&virtual_index);
3443                   break;
3444                 }
3445               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3446               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3447               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3448                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3449                 exception);
3450               virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3451                 *virtual_nexus);
3452               break;
3453             }
3454             case HorizontalTileEdgeVirtualPixelMethod:
3455             {
3456               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3457               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3458                 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3459                 *virtual_nexus,exception);
3460               virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3461                 *virtual_nexus);
3462               break;
3463             }
3464             case VerticalTileEdgeVirtualPixelMethod:
3465             {
3466               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3467               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3468                 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3469                 *virtual_nexus,exception);
3470               virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3471                 *virtual_nexus);
3472               break;
3473             }
3474           }
3475           if (p == (const PixelPacket *) NULL)
3476             break;
3477           *q++=(*p);
3478           if ((indexes != (IndexPacket *) NULL) &&
3479               (virtual_indexes != (const IndexPacket *) NULL))
3480             *indexes++=(*virtual_indexes);
3481           continue;
3482         }
3483       /*
3484         Transfer a run of pixels.
3485       */
3486       p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3487         (size_t) length,1UL,*virtual_nexus,exception);
3488       if (p == (const PixelPacket *) NULL)
3489         break;
3490       virtual_indexes=GetVirtualIndexesFromNexus(cache_info,*virtual_nexus);
3491       (void) memcpy(q,p,(size_t) length*sizeof(*p));
3492       q+=length;
3493       if ((indexes != (IndexPacket *) NULL) &&
3494           (virtual_indexes != (const IndexPacket *) NULL))
3495         {
3496           (void) memcpy(indexes,virtual_indexes,(size_t) length*
3497             sizeof(*virtual_indexes));
3498           indexes+=length;
3499         }
3500     }
3501   }
3502   virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3503   return(pixels);
3504 }
3505 \f
3506 /*
3507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3508 %                                                                             %
3509 %                                                                             %
3510 %                                                                             %
3511 +   G e t V i r t u a l P i x e l C a c h e                                   %
3512 %                                                                             %
3513 %                                                                             %
3514 %                                                                             %
3515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3516 %
3517 %  GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3518 %  cache as defined by the geometry parameters.   A pointer to the pixels
3519 %  is returned if the pixels are transferred, otherwise a NULL is returned.
3520 %
3521 %  The format of the GetVirtualPixelCache() method is:
3522 %
3523 %      const PixelPacket *GetVirtualPixelCache(const Image *image,
3524 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3525 %        const ssize_t y,const size_t columns,const size_t rows,
3526 %        ExceptionInfo *exception)
3527 %
3528 %  A description of each parameter follows:
3529 %
3530 %    o image: the image.
3531 %
3532 %    o virtual_pixel_method: the virtual pixel method.
3533 %
3534 %    o x,y,columns,rows:  These values define the perimeter of a region of
3535 %      pixels.
3536 %
3537 %    o exception: return any errors or warnings in this structure.
3538 %
3539 */
3540 static const PixelPacket *GetVirtualPixelCache(const Image *image,
3541   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3542   const size_t columns,const size_t rows,ExceptionInfo *exception)
3543 {
3544   CacheInfo
3545     *cache_info;
3546
3547   const int
3548     id = GetOpenMPThreadId();
3549
3550   assert(image != (const Image *) NULL);
3551   assert(image->signature == MagickSignature);
3552   assert(image->cache != (Cache) NULL);
3553   cache_info=(CacheInfo *) image->cache;
3554   assert(cache_info->signature == MagickSignature);
3555   assert(id < (int) cache_info->number_threads);
3556   return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3557     cache_info->nexus_info[id],exception));
3558 }
3559 \f
3560 /*
3561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562 %                                                                             %
3563 %                                                                             %
3564 %                                                                             %
3565 %   G e t V i r t u a l P i x e l Q u e u e                                   %
3566 %                                                                             %
3567 %                                                                             %
3568 %                                                                             %
3569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3570 %
3571 %  GetVirtualPixelQueue() returns the virtual pixels associated with the
3572 %  last call to QueueAuthenticPixels() or GetVirtualPixels().
3573 %
3574 %  The format of the GetVirtualPixelQueue() method is:
3575 %
3576 %      const PixelPacket *GetVirtualPixelQueue(const Image image)
3577 %
3578 %  A description of each parameter follows:
3579 %
3580 %    o image: the image.
3581 %
3582 */
3583 MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3584 {
3585   CacheInfo
3586     *cache_info;
3587
3588   const int
3589     id = GetOpenMPThreadId();
3590
3591   assert(image != (const Image *) NULL);
3592   assert(image->signature == MagickSignature);
3593   assert(image->cache != (Cache) NULL);
3594   cache_info=(CacheInfo *) image->cache;
3595   assert(cache_info->signature == MagickSignature);
3596   if (cache_info->methods.get_virtual_pixels_handler !=
3597        (GetVirtualPixelsHandler) NULL)
3598     return(cache_info->methods.get_virtual_pixels_handler(image));
3599   assert(id < (int) cache_info->number_threads);
3600   return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3601 }
3602 \f
3603 /*
3604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605 %                                                                             %
3606 %                                                                             %
3607 %                                                                             %
3608 %   G e t V i r t u a l P i x e l s                                           %
3609 %                                                                             %
3610 %                                                                             %
3611 %                                                                             %
3612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3613 %
3614 %  GetVirtualPixels() returns an immutable pixel region. If the
3615 %  region is successfully accessed, a pointer to it is returned, otherwise
3616 %  NULL is returned.  The returned pointer may point to a temporary working
3617 %  copy of the pixels or it may point to the original pixels in memory.
3618 %  Performance is maximized if the selected region is part of one row, or one
3619 %  or more full rows, since there is opportunity to access the pixels in-place
3620 %  (without a copy) if the image is in memory, or in a memory-mapped file.  The
3621 %  returned pointer must *never* be deallocated by the user.
3622 %
3623 %  Pixels accessed via the returned pointer represent a simple array of type
3624 %  PixelPacket.  If the image type is CMYK or the storage class is PseudoClass,
3625 %  call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3626 %  the black color component or to obtain the colormap indexes (of type
3627 %  IndexPacket) corresponding to the region.
3628 %
3629 %  If you plan to modify the pixels, use GetAuthenticPixels() instead.
3630 %
3631 %  Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3632 %  safe.  In a threaded environment, use GetCacheViewVirtualPixels() or
3633 %  GetCacheViewAuthenticPixels() instead.
3634 %
3635 %  The format of the GetVirtualPixels() method is:
3636 %
3637 %      const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3638 %        const ssize_t y,const size_t columns,const size_t rows,
3639 %        ExceptionInfo *exception)
3640 %
3641 %  A description of each parameter follows:
3642 %
3643 %    o image: the image.
3644 %
3645 %    o x,y,columns,rows:  These values define the perimeter of a region of
3646 %      pixels.
3647 %
3648 %    o exception: return any errors or warnings in this structure.
3649 %
3650 */
3651 MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3652   const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3653   ExceptionInfo *exception)
3654 {
3655   CacheInfo
3656     *cache_info;
3657
3658   const int
3659     id = GetOpenMPThreadId();
3660
3661   assert(image != (const Image *) NULL);
3662   assert(image->signature == MagickSignature);
3663   assert(image->cache != (Cache) NULL);
3664   cache_info=(CacheInfo *) image->cache;
3665   assert(cache_info->signature == MagickSignature);
3666   if (cache_info->methods.get_virtual_pixel_handler !=
3667        (GetVirtualPixelHandler) NULL)
3668     return(cache_info->methods.get_virtual_pixel_handler(image,
3669       GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3670   assert(id < (int) cache_info->number_threads);
3671   return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3672     columns,rows,cache_info->nexus_info[id],exception));
3673 }
3674 \f
3675 /*
3676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3677 %                                                                             %
3678 %                                                                             %
3679 %                                                                             %
3680 +   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                         %
3681 %                                                                             %
3682 %                                                                             %
3683 %                                                                             %
3684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3685 %
3686 %  GetVirtualPixelsCache() returns the pixels associated with the last call
3687 %  to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3688 %
3689 %  The format of the GetVirtualPixelsCache() method is:
3690 %
3691 %      PixelPacket *GetVirtualPixelsCache(const Image *image)
3692 %
3693 %  A description of each parameter follows:
3694 %
3695 %    o image: the image.
3696 %
3697 */
3698 static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3699 {
3700   CacheInfo
3701     *cache_info;
3702
3703   const int
3704     id = GetOpenMPThreadId();
3705
3706   assert(image != (const Image *) NULL);
3707   assert(image->signature == MagickSignature);
3708   assert(image->cache != (Cache) NULL);
3709   cache_info=(CacheInfo *) image->cache;
3710   assert(cache_info->signature == MagickSignature);
3711   assert(id < (int) cache_info->number_threads);
3712   return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3713 }
3714 \f
3715 /*
3716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3717 %                                                                             %
3718 %                                                                             %
3719 %                                                                             %
3720 +   G e t V i r t u a l P i x e l s N e x u s                                 %
3721 %                                                                             %
3722 %                                                                             %
3723 %                                                                             %
3724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3725 %
3726 %  GetVirtualPixelsNexus() returns the pixels associated with the specified
3727 %  cache nexus.
3728 %
3729 %  The format of the GetVirtualPixelsNexus() method is:
3730 %
3731 %      const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3732 %        NexusInfo *nexus_info)
3733 %
3734 %  A description of each parameter follows:
3735 %
3736 %    o cache: the pixel cache.
3737 %
3738 %    o nexus_info: the cache nexus to return the colormap pixels.
3739 %
3740 */
3741 MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3742   NexusInfo *nexus_info)
3743 {
3744   CacheInfo
3745     *cache_info;
3746
3747   assert(cache != (Cache) NULL);
3748   cache_info=(CacheInfo *) cache;
3749   assert(cache_info->signature == MagickSignature);
3750   if (cache_info->storage_class == UndefinedClass)
3751     return((PixelPacket *) NULL);
3752   return((const PixelPacket *) nexus_info->pixels);
3753 }
3754 \f
3755 /*
3756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3757 %                                                                             %
3758 %                                                                             %
3759 %                                                                             %
3760 +   M a s k P i x e l C a c h e N e x u s                                     %
3761 %                                                                             %
3762 %                                                                             %
3763 %                                                                             %
3764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3765 %
3766 %  MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3767 %  The method returns MagickTrue if the pixel region is masked, otherwise
3768 %  MagickFalse.
3769 %
3770 %  The format of the MaskPixelCacheNexus() method is:
3771 %
3772 %      MagickBooleanType MaskPixelCacheNexus(Image *image,
3773 %        NexusInfo *nexus_info,ExceptionInfo *exception)
3774 %
3775 %  A description of each parameter follows:
3776 %
3777 %    o image: the image.
3778 %
3779 %    o nexus_info: the cache nexus to clip.
3780 %
3781 %    o exception: return any errors or warnings in this structure.
3782 %
3783 */
3784
3785 static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3786   const MagickRealType alpha,const MagickPixelPacket *q,
3787   const MagickRealType beta,MagickPixelPacket *composite)
3788 {
3789   MagickRealType
3790     gamma;
3791
3792   if (alpha == TransparentOpacity)
3793     {
3794       *composite=(*q);
3795       return;
3796     }
3797   gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3798   gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3799   composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3800   composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3801   composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3802   if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3803     composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3804 }
3805
3806 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3807   ExceptionInfo *exception)
3808 {
3809   CacheInfo
3810     *cache_info;
3811
3812   MagickPixelPacket
3813     alpha,
3814     beta;
3815
3816   MagickSizeType
3817     number_pixels;
3818
3819   NexusInfo
3820     **clip_nexus,
3821     **image_nexus;
3822
3823   register const PixelPacket
3824     *restrict r;
3825
3826   register IndexPacket
3827     *restrict nexus_indexes,
3828     *restrict indexes;
3829
3830   register PixelPacket
3831     *restrict p,
3832     *restrict q;
3833
3834   register ssize_t
3835     i;
3836
3837   /*
3838     Apply clip mask.
3839   */
3840   if (image->debug != MagickFalse)
3841     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3842   if (image->mask == (Image *) NULL)
3843     return(MagickFalse);
3844   cache_info=(CacheInfo *) image->cache;
3845   if (cache_info == (Cache) NULL)
3846     return(MagickFalse);
3847   image_nexus=AcquirePixelCacheNexus(1);
3848   clip_nexus=AcquirePixelCacheNexus(1);
3849   if ((image_nexus == (NexusInfo **) NULL) ||
3850       (clip_nexus == (NexusInfo **) NULL))
3851     ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3852   p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3853     nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3854     image_nexus[0],exception);
3855   indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3856   q=nexus_info->pixels;
3857   nexus_indexes=nexus_info->indexes;
3858   r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3859     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3860     nexus_info->region.height,clip_nexus[0],&image->exception);
3861   GetMagickPixelPacket(image,&alpha);
3862   GetMagickPixelPacket(image,&beta);
3863   number_pixels=(MagickSizeType) nexus_info->region.width*
3864     nexus_info->region.height;
3865   for (i=0; i < (ssize_t) number_pixels; i++)
3866   {
3867     if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3868       break;
3869     SetMagickPixelPacket(image,p,indexes+i,&alpha);
3870     SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3871     MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3872       &alpha,alpha.opacity,&beta);
3873     q->red=ClampToQuantum(beta.red);
3874     q->green=ClampToQuantum(beta.green);
3875     q->blue=ClampToQuantum(beta.blue);
3876     q->opacity=ClampToQuantum(beta.opacity);
3877     if (cache_info->active_index_channel != MagickFalse)
3878       nexus_indexes[i]=indexes[i];
3879     p++;
3880     q++;
3881     r++;
3882   }
3883   clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3884   image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3885   if (i < (ssize_t) number_pixels)
3886     return(MagickFalse);
3887   return(MagickTrue);
3888 }
3889 \f
3890 /*
3891 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3892 %                                                                             %
3893 %                                                                             %
3894 %                                                                             %
3895 +   O p e n P i x e l C a c h e                                               %
3896 %                                                                             %
3897 %                                                                             %
3898 %                                                                             %
3899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3900 %
3901 %  OpenPixelCache() allocates the pixel cache.  This includes defining the cache
3902 %  dimensions, allocating space for the image pixels and optionally the
3903 %  colormap indexes, and memory mapping the cache if it is disk based.  The
3904 %  cache nexus array is initialized as well.
3905 %
3906 %  The format of the OpenPixelCache() method is:
3907 %
3908 %      MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3909 %        ExceptionInfo *exception)
3910 %
3911 %  A description of each parameter follows:
3912 %
3913 %    o image: the image.
3914 %
3915 %    o mode: ReadMode, WriteMode, or IOMode.
3916 %
3917 %    o exception: return any errors or warnings in this structure.
3918 %
3919 */
3920
3921 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3922 {
3923   cache_info->mapped=MagickFalse;
3924   cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3925     cache_info->length);
3926   if (cache_info->pixels == (PixelPacket *) NULL)
3927     {
3928       cache_info->mapped=MagickTrue;
3929       cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3930         cache_info->length);
3931     }
3932 }
3933
3934 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3935 {
3936   CacheInfo
3937     *cache_info;
3938
3939   MagickOffsetType
3940     count,
3941     extent,
3942     offset;
3943
3944   cache_info=(CacheInfo *) image->cache;
3945   if (image->debug != MagickFalse)
3946     {
3947       char
3948         format[MaxTextExtent],
3949         message[MaxTextExtent];
3950
3951       (void) FormatMagickSize(length,MagickFalse,format);
3952       (void) FormatMagickString(message,MaxTextExtent,
3953         "extend %s (%s[%d], disk, %sB)",cache_info->filename,
3954         cache_info->cache_filename,cache_info->file,format);
3955       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3956     }
3957   if (length != (MagickSizeType) ((MagickOffsetType) length))
3958     return(MagickFalse);
3959   extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3960   if (extent < 0)
3961     return(MagickFalse);
3962   if ((MagickSizeType) extent >= length)
3963     return(MagickTrue);
3964   offset=(MagickOffsetType) length-1;
3965   count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3966   return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3967 }
3968
3969 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3970   ExceptionInfo *exception)
3971 {
3972   char
3973     format[MaxTextExtent],
3974     message[MaxTextExtent];
3975
3976   CacheInfo
3977     *cache_info,
3978     source_info;
3979
3980   MagickSizeType
3981     length,
3982     number_pixels;
3983
3984   MagickStatusType
3985     status;
3986
3987   size_t
3988     columns,
3989     packet_size;
3990
3991   assert(image != (const Image *) NULL);
3992   assert(image->signature == MagickSignature);
3993   assert(image->cache != (Cache) NULL);
3994   if (image->debug != MagickFalse)
3995     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3996   if ((image->columns == 0) || (image->rows == 0))
3997     ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3998   cache_info=(CacheInfo *) image->cache;
3999   assert(cache_info->signature == MagickSignature);
4000   source_info=(*cache_info);
4001   source_info.file=(-1);
4002   (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4003     image->filename,(double) GetImageIndexInList(image));
4004   cache_info->mode=mode;
4005   cache_info->rows=image->rows;
4006   cache_info->columns=image->columns;
4007   cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4008     (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
4009   if (image->ping != MagickFalse)
4010     {
4011       cache_info->storage_class=image->storage_class;
4012       cache_info->colorspace=image->colorspace;
4013       cache_info->type=PingCache;
4014       cache_info->pixels=(PixelPacket *) NULL;
4015       cache_info->indexes=(IndexPacket *) NULL;
4016       cache_info->length=0;
4017       return(MagickTrue);
4018     }
4019   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4020   packet_size=sizeof(PixelPacket);
4021   if (cache_info->active_index_channel != MagickFalse)
4022     packet_size+=sizeof(IndexPacket);
4023   length=number_pixels*packet_size;
4024   columns=(size_t) (length/cache_info->rows/packet_size);
4025   if (cache_info->columns != columns)
4026     ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4027       image->filename);
4028   cache_info->length=length;
4029   status=AcquireMagickResource(AreaResource,cache_info->length);
4030   length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4031   if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4032     {
4033       status=AcquireMagickResource(MemoryResource,cache_info->length);
4034       if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4035           (cache_info->type == MemoryCache))
4036         {
4037           AllocatePixelCachePixels(cache_info);
4038           if (cache_info->pixels == (PixelPacket *) NULL)
4039             cache_info->pixels=source_info.pixels;
4040           else
4041             {
4042               /*
4043                 Create memory pixel cache.
4044               */
4045               if (image->debug != MagickFalse)
4046                 {
4047                   (void) FormatMagickSize(cache_info->length,MagickTrue,
4048                     format);
4049                   (void) FormatMagickString(message,MaxTextExtent,
4050                     "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
4051                     cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4052                     (double) cache_info->columns,(double) cache_info->rows,
4053                     format);
4054                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4055                     message);
4056                 }
4057               cache_info->storage_class=image->storage_class;
4058               cache_info->colorspace=image->colorspace;
4059               cache_info->type=MemoryCache;
4060               cache_info->indexes=(IndexPacket *) NULL;
4061               if (cache_info->active_index_channel != MagickFalse)
4062                 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4063                   number_pixels);
4064               if (source_info.storage_class != UndefinedClass)
4065                 {
4066                   status|=ClonePixelCachePixels(cache_info,&source_info,
4067                     exception);
4068                   RelinquishPixelCachePixels(&source_info);
4069                 }
4070               return(MagickTrue);
4071             }
4072         }
4073       RelinquishMagickResource(MemoryResource,cache_info->length);
4074     }
4075   /*
4076     Create pixel cache on disk.
4077   */
4078   status=AcquireMagickResource(DiskResource,cache_info->length);
4079   if (status == MagickFalse)
4080     {
4081       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4082         "CacheResourcesExhausted","`%s'",image->filename);
4083       return(MagickFalse);
4084     }
4085   if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4086     {
4087       RelinquishMagickResource(DiskResource,cache_info->length);
4088       ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4089         image->filename);
4090       return(MagickFalse);
4091     }
4092   status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4093     cache_info->length);
4094   if (status == MagickFalse)
4095     {
4096       ThrowFileException(exception,CacheError,"UnableToExtendCache",
4097         image->filename);
4098       return(MagickFalse);
4099     }
4100   cache_info->storage_class=image->storage_class;
4101   cache_info->colorspace=image->colorspace;
4102   length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4103   status=AcquireMagickResource(AreaResource,cache_info->length);
4104   if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4105     cache_info->type=DiskCache;
4106   else
4107     {
4108       status=AcquireMagickResource(MapResource,cache_info->length);
4109       if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4110           (cache_info->type != MemoryCache))
4111         cache_info->type=DiskCache;
4112       else
4113         {
4114           cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4115             cache_info->offset,(size_t) cache_info->length);
4116           if (cache_info->pixels == (PixelPacket *) NULL)
4117             {
4118               cache_info->pixels=source_info.pixels;
4119               cache_info->type=DiskCache;
4120             }
4121           else
4122             {
4123               /*
4124                 Create file-backed memory-mapped pixel cache.
4125               */
4126               (void) ClosePixelCacheOnDisk(cache_info);
4127               cache_info->type=MapCache;
4128               cache_info->mapped=MagickTrue;
4129               cache_info->indexes=(IndexPacket *) NULL;
4130               if (cache_info->active_index_channel != MagickFalse)
4131                 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4132                   number_pixels);
4133               if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4134                 {
4135                   status=ClonePixelCachePixels(cache_info,&source_info,
4136                     exception);
4137                   RelinquishPixelCachePixels(&source_info);
4138                 }
4139               if (image->debug != MagickFalse)
4140                 {
4141                   (void) FormatMagickSize(cache_info->length,MagickTrue,
4142                     format);
4143                   (void) FormatMagickString(message,MaxTextExtent,
4144                     "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
4145                     cache_info->filename,cache_info->cache_filename,
4146                     cache_info->file,(double) cache_info->columns,(double)
4147                     cache_info->rows,format);
4148                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4149                     message);
4150                 }
4151               return(MagickTrue);
4152             }
4153         }
4154       RelinquishMagickResource(MapResource,cache_info->length);
4155     }
4156   if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4157     {
4158       status=ClonePixelCachePixels(cache_info,&source_info,exception);
4159       RelinquishPixelCachePixels(&source_info);
4160     }
4161   if (image->debug != MagickFalse)
4162     {
4163       (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4164       (void) FormatMagickString(message,MaxTextExtent,
4165         "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4166         cache_info->cache_filename,cache_info->file,(double)
4167         cache_info->columns,(double) cache_info->rows,format);
4168       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4169     }
4170   return(MagickTrue);
4171 }
4172 \f
4173 /*
4174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4175 %                                                                             %
4176 %                                                                             %
4177 %                                                                             %
4178 +   P e r s i s t P i x e l C a c h e                                         %
4179 %                                                                             %
4180 %                                                                             %
4181 %                                                                             %
4182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4183 %
4184 %  PersistPixelCache() attaches to or initializes a persistent pixel cache.  A
4185 %  persistent pixel cache is one that resides on disk and is not destroyed
4186 %  when the program exits.
4187 %
4188 %  The format of the PersistPixelCache() method is:
4189 %
4190 %      MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4191 %        const MagickBooleanType attach,MagickOffsetType *offset,
4192 %        ExceptionInfo *exception)
4193 %
4194 %  A description of each parameter follows:
4195 %
4196 %    o image: the image.
4197 %
4198 %    o filename: the persistent pixel cache filename.
4199 %
4200 %    o attach: A value other than zero initializes the persistent pixel
4201 %      cache.
4202 %
4203 %    o initialize: A value other than zero initializes the persistent pixel
4204 %      cache.
4205 %
4206 %    o offset: the offset in the persistent cache to store pixels.
4207 %
4208 %    o exception: return any errors or warnings in this structure.
4209 %
4210 */
4211 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4212   const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4213   ExceptionInfo *exception)
4214 {
4215   CacheInfo
4216     *cache_info,
4217     *clone_info;
4218
4219   Image
4220     clone_image;
4221
4222   MagickBooleanType
4223     status;
4224
4225   ssize_t
4226     page_size;
4227
4228   assert(image != (Image *) NULL);
4229   assert(image->signature == MagickSignature);
4230   if (image->debug != MagickFalse)
4231     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4232   assert(image->cache != (void *) NULL);
4233   assert(filename != (const char *) NULL);
4234   assert(offset != (MagickOffsetType *) NULL);
4235   page_size=GetMagickPageSize();
4236   cache_info=(CacheInfo *) image->cache;
4237   assert(cache_info->signature == MagickSignature);
4238   if (attach != MagickFalse)
4239     {
4240       /*
4241         Attach existing persistent pixel cache.
4242       */
4243       if (image->debug != MagickFalse)
4244         (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4245           "attach persistent cache");
4246       (void) CopyMagickString(cache_info->cache_filename,filename,
4247         MaxTextExtent);
4248       cache_info->type=DiskCache;
4249       cache_info->offset=(*offset);
4250       if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4251         return(MagickFalse);
4252       *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4253       return(MagickTrue);
4254     }
4255   if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4256       (cache_info->reference_count == 1))
4257     {
4258       LockSemaphoreInfo(cache_info->semaphore);
4259       if ((cache_info->mode != ReadMode) &&
4260           (cache_info->type != MemoryCache) &&
4261           (cache_info->reference_count == 1))
4262         {
4263           int
4264             status;
4265
4266           /*
4267             Usurp existing persistent pixel cache.
4268           */
4269           status=rename(cache_info->cache_filename,filename);
4270           if (status == 0)
4271             {
4272               (void) CopyMagickString(cache_info->cache_filename,filename,
4273                 MaxTextExtent);
4274               *offset+=cache_info->length+page_size-(cache_info->length %
4275                 page_size);
4276               UnlockSemaphoreInfo(cache_info->semaphore);
4277               cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4278               if (image->debug != MagickFalse)
4279                 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4280                   "Usurp resident persistent cache");
4281               return(MagickTrue);
4282             }
4283         }
4284       UnlockSemaphoreInfo(cache_info->semaphore);
4285     }
4286   /*
4287     Clone persistent pixel cache.
4288   */
4289   clone_image=(*image);
4290   clone_info=(CacheInfo *) clone_image.cache;
4291   image->cache=ClonePixelCache(cache_info);
4292   cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4293   (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4294   cache_info->type=DiskCache;
4295   cache_info->offset=(*offset);
4296   cache_info=(CacheInfo *) image->cache;
4297   status=OpenPixelCache(image,IOMode,exception);
4298   if (status != MagickFalse)
4299     status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4300   *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4301   clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4302   return(status);
4303 }
4304 \f
4305 /*
4306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4307 %                                                                             %
4308 %                                                                             %
4309 %                                                                             %
4310 +   Q u e u e A u t h e n t i c N e x u s                                     %
4311 %                                                                             %
4312 %                                                                             %
4313 %                                                                             %
4314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4315 %
4316 %  QueueAuthenticNexus() allocates an region to store image pixels as defined
4317 %  by the region rectangle and returns a pointer to the region.  This region is
4318 %  subsequently transferred from the pixel cache with
4319 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4320 %  pixels are transferred, otherwise a NULL is returned.
4321 %
4322 %  The format of the QueueAuthenticNexus() method is:
4323 %
4324 %      PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4325 %        const ssize_t y,const size_t columns,const size_t rows,
4326 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4327 %
4328 %  A description of each parameter follows:
4329 %
4330 %    o image: the image.
4331 %
4332 %    o x,y,columns,rows:  These values define the perimeter of a region of
4333 %      pixels.
4334 %
4335 %    o nexus_info: the cache nexus to set.
4336 %
4337 %    o exception: return any errors or warnings in this structure.
4338 %
4339 */
4340 MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4341   const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4342   ExceptionInfo *exception)
4343 {
4344   CacheInfo
4345     *cache_info;
4346
4347   MagickOffsetType
4348     offset;
4349
4350   MagickSizeType
4351     number_pixels;
4352
4353   RectangleInfo
4354     region;
4355
4356   /*
4357     Validate pixel cache geometry.
4358   */
4359   assert(image != (const Image *) NULL);
4360   assert(image->signature == MagickSignature);
4361   assert(image->cache != (Cache) NULL);
4362   cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4363   assert(cache_info->signature == MagickSignature);
4364   if (cache_info == (Cache) NULL)
4365     return((PixelPacket *) NULL);
4366   if ((cache_info->columns == 0) && (cache_info->rows == 0))
4367     {
4368       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4369         "NoPixelsDefinedInCache","`%s'",image->filename);
4370       return((PixelPacket *) NULL);
4371     }
4372   if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4373       (y >= (ssize_t) cache_info->rows))
4374     {
4375       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4376         "PixelsAreNotAuthentic","`%s'",image->filename);
4377       return((PixelPacket *) NULL);
4378     }
4379   offset=(MagickOffsetType) y*cache_info->columns+x;
4380   if (offset < 0)
4381     return((PixelPacket *) NULL);
4382   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4383   offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4384   if ((MagickSizeType) offset >= number_pixels)
4385     return((PixelPacket *) NULL);
4386   /*
4387     Return pixel cache.
4388   */
4389   region.x=x;
4390   region.y=y;
4391   region.width=columns;
4392   region.height=rows;
4393   return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4394 }
4395 \f
4396 /*
4397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4398 %                                                                             %
4399 %                                                                             %
4400 %                                                                             %
4401 +   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                         %
4402 %                                                                             %
4403 %                                                                             %
4404 %                                                                             %
4405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4406 %
4407 %  QueueAuthenticPixelsCache() allocates an region to store image pixels as
4408 %  defined by the region rectangle and returns a pointer to the region.  This
4409 %  region is subsequently transferred from the pixel cache with
4410 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4411 %  pixels are transferred, otherwise a NULL is returned.
4412 %
4413 %  The format of the QueueAuthenticPixelsCache() method is:
4414 %
4415 %      PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4416 %        const ssize_t y,const size_t columns,const size_t rows,
4417 %        ExceptionInfo *exception)
4418 %
4419 %  A description of each parameter follows:
4420 %
4421 %    o image: the image.
4422 %
4423 %    o x,y,columns,rows:  These values define the perimeter of a region of
4424 %      pixels.
4425 %
4426 %    o exception: return any errors or warnings in this structure.
4427 %
4428 */
4429 static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4430   const ssize_t y,const size_t columns,const size_t rows,
4431   ExceptionInfo *exception)
4432 {
4433   CacheInfo
4434     *cache_info;
4435
4436   const int
4437     id = GetOpenMPThreadId();
4438
4439   assert(image != (const Image *) NULL);
4440   assert(image->signature == MagickSignature);
4441   assert(image->cache != (Cache) NULL);
4442   cache_info=(CacheInfo *) image->cache;
4443   assert(cache_info->signature == MagickSignature);
4444   assert(id < (int) cache_info->number_threads);
4445   return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4446     exception));
4447 }
4448 \f
4449 /*
4450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4451 %                                                                             %
4452 %                                                                             %
4453 %                                                                             %
4454 %   Q u e u e A u t h e n t i c P i x e l s                                   %
4455 %                                                                             %
4456 %                                                                             %
4457 %                                                                             %
4458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4459 %
4460 %  QueueAuthenticPixels() queues a mutable pixel region.  If the region is
4461 %  successfully intialized a pointer to a PixelPacket array representing the
4462 %  region is returned, otherwise NULL is returned.  The returned pointer may
4463 %  point to a temporary working buffer for the pixels or it may point to the
4464 %  final location of the pixels in memory.
4465 %
4466 %  Write-only access means that any existing pixel values corresponding to
4467 %  the region are ignored.  This is useful if the initial image is being
4468 %  created from scratch, or if the existing pixel values are to be
4469 %  completely replaced without need to refer to their pre-existing values.
4470 %  The application is free to read and write the pixel buffer returned by
4471 %  QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4472 %  initialize the pixel array values. Initializing pixel array values is the
4473 %  application's responsibility.
4474 %
4475 %  Performance is maximized if the selected region is part of one row, or
4476 %  one or more full rows, since then there is opportunity to access the
4477 %  pixels in-place (without a copy) if the image is in memory, or in a
4478 %  memory-mapped file. The returned pointer must *never* be deallocated
4479 %  by the user.
4480 %
4481 %  Pixels accessed via the returned pointer represent a simple array of type
4482 %  PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4483 %  call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4484 %  the black color component or the colormap indexes (of type IndexPacket)
4485 %  corresponding to the region.  Once the PixelPacket (and/or IndexPacket)
4486 %  array has been updated, the changes must be saved back to the underlying
4487 %  image using SyncAuthenticPixels() or they may be lost.
4488 %
4489 %  The format of the QueueAuthenticPixels() method is:
4490 %
4491 %      PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4492 %        const ssize_t y,const size_t columns,const size_t rows,
4493 %        ExceptionInfo *exception)
4494 %
4495 %  A description of each parameter follows:
4496 %
4497 %    o image: the image.
4498 %
4499 %    o x,y,columns,rows:  These values define the perimeter of a region of
4500 %      pixels.
4501 %
4502 %    o exception: return any errors or warnings in this structure.
4503 %
4504 */
4505 MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4506   const ssize_t y,const size_t columns,const size_t rows,
4507   ExceptionInfo *exception)
4508 {
4509   CacheInfo
4510     *cache_info;
4511
4512   const int
4513     id = GetOpenMPThreadId();
4514
4515   assert(image != (Image *) NULL);
4516   assert(image->signature == MagickSignature);
4517   assert(image->cache != (Cache) NULL);
4518   cache_info=(CacheInfo *) image->cache;
4519   assert(cache_info->signature == MagickSignature);
4520   if (cache_info->methods.queue_authentic_pixels_handler !=
4521        (QueueAuthenticPixelsHandler) NULL)
4522     return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4523       rows,exception));
4524   assert(id < (int) cache_info->number_threads);
4525   return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4526     exception));
4527 }
4528 \f
4529 /*
4530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4531 %                                                                             %
4532 %                                                                             %
4533 %                                                                             %
4534 +   R e a d P i x e l C a c h e I n d e x e s                                 %
4535 %                                                                             %
4536 %                                                                             %
4537 %                                                                             %
4538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4539 %
4540 %  ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4541 %  the pixel cache.
4542 %
4543 %  The format of the ReadPixelCacheIndexes() method is:
4544 %
4545 %      MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4546 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4547 %
4548 %  A description of each parameter follows:
4549 %
4550 %    o cache_info: the pixel cache.
4551 %
4552 %    o nexus_info: the cache nexus to read the colormap indexes.
4553 %
4554 %    o exception: return any errors or warnings in this structure.
4555 %
4556 */
4557 static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4558   NexusInfo *nexus_info,ExceptionInfo *exception)
4559 {
4560   MagickOffsetType
4561     count,
4562     offset;
4563
4564   MagickSizeType
4565     extent,
4566     length;
4567
4568   register IndexPacket
4569     *restrict q;
4570
4571   register ssize_t
4572     y;
4573
4574   size_t
4575     rows;
4576
4577   if (cache_info->active_index_channel == MagickFalse)
4578     return(MagickFalse);
4579   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4580     return(MagickTrue);
4581   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4582     nexus_info->region.x;
4583   length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4584   rows=nexus_info->region.height;
4585   extent=length*rows;
4586   q=nexus_info->indexes;
4587   switch (cache_info->type)
4588   {
4589     case MemoryCache:
4590     case MapCache:
4591     {
4592       register IndexPacket
4593         *restrict p;
4594
4595       /*
4596         Read indexes from memory.
4597       */
4598       if ((cache_info->columns == nexus_info->region.width) &&
4599           (extent == (MagickSizeType) ((size_t) extent)))
4600         {
4601           length=extent;
4602           rows=1UL;
4603         }
4604       p=cache_info->indexes+offset;
4605       for (y=0; y < (ssize_t) rows; y++)
4606       {
4607         (void) memcpy(q,p,(size_t) length);
4608         p+=cache_info->columns;
4609         q+=nexus_info->region.width;
4610       }
4611       break;
4612     }
4613     case DiskCache:
4614     {
4615       /*
4616         Read indexes from disk.
4617       */
4618       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4619         {
4620           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4621             cache_info->cache_filename);
4622           return(MagickFalse);
4623         }
4624       if ((cache_info->columns == nexus_info->region.width) &&
4625           (extent <= MagickMaxBufferExtent))
4626         {
4627           length=extent;
4628           rows=1UL;
4629         }
4630       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4631       for (y=0; y < (ssize_t) rows; y++)
4632       {
4633         count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4634           sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4635         if ((MagickSizeType) count < length)
4636           break;
4637         offset+=cache_info->columns;
4638         q+=nexus_info->region.width;
4639       }
4640       if (y < (ssize_t) rows)
4641         {
4642           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4643             cache_info->cache_filename);
4644           return(MagickFalse);
4645         }
4646       break;
4647     }
4648     default:
4649       break;
4650   }
4651   if ((cache_info->debug != MagickFalse) &&
4652       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4653     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4654       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4655       nexus_info->region.width,(double) nexus_info->region.height,(double)
4656       nexus_info->region.x,(double) nexus_info->region.y);
4657   return(MagickTrue);
4658 }
4659 \f
4660 /*
4661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4662 %                                                                             %
4663 %                                                                             %
4664 %                                                                             %
4665 +   R e a d P i x e l C a c h e P i x e l s                                   %
4666 %                                                                             %
4667 %                                                                             %
4668 %                                                                             %
4669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4670 %
4671 %  ReadPixelCachePixels() reads pixels from the specified region of the pixel
4672 %  cache.
4673 %
4674 %  The format of the ReadPixelCachePixels() method is:
4675 %
4676 %      MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4677 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4678 %
4679 %  A description of each parameter follows:
4680 %
4681 %    o cache_info: the pixel cache.
4682 %
4683 %    o nexus_info: the cache nexus to read the pixels.
4684 %
4685 %    o exception: return any errors or warnings in this structure.
4686 %
4687 */
4688 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4689   NexusInfo *nexus_info,ExceptionInfo *exception)
4690 {
4691   MagickOffsetType
4692     count,
4693     offset;
4694
4695   MagickSizeType
4696     extent,
4697     length;
4698
4699   register PixelPacket
4700     *restrict q;
4701
4702   register ssize_t
4703     y;
4704
4705   size_t
4706     rows;
4707
4708   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4709     return(MagickTrue);
4710   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4711     nexus_info->region.x;
4712   length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4713   rows=nexus_info->region.height;
4714   extent=length*rows;
4715   q=nexus_info->pixels;
4716   switch (cache_info->type)
4717   {
4718     case MemoryCache:
4719     case MapCache:
4720     {
4721       register PixelPacket
4722         *restrict p;
4723
4724       /*
4725         Read pixels from memory.
4726       */
4727       if ((cache_info->columns == nexus_info->region.width) &&
4728           (extent == (MagickSizeType) ((size_t) extent)))
4729         {
4730           length=extent;
4731           rows=1UL;
4732         }
4733       p=cache_info->pixels+offset;
4734       for (y=0; y < (ssize_t) rows; y++)
4735       {
4736         (void) memcpy(q,p,(size_t) length);
4737         p+=cache_info->columns;
4738         q+=nexus_info->region.width;
4739       }
4740       break;
4741     }
4742     case DiskCache:
4743     {
4744       /*
4745         Read pixels from disk.
4746       */
4747       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4748         {
4749           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4750             cache_info->cache_filename);
4751           return(MagickFalse);
4752         }
4753       if ((cache_info->columns == nexus_info->region.width) &&
4754           (extent <= MagickMaxBufferExtent))
4755         {
4756           length=extent;
4757           rows=1UL;
4758         }
4759       for (y=0; y < (ssize_t) rows; y++)
4760       {
4761         count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4762           sizeof(*q),length,(unsigned char *) q);
4763         if ((MagickSizeType) count < length)
4764           break;
4765         offset+=cache_info->columns;
4766         q+=nexus_info->region.width;
4767       }
4768       if (y < (ssize_t) rows)
4769         {
4770           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4771             cache_info->cache_filename);
4772           return(MagickFalse);
4773         }
4774       break;
4775     }
4776     default:
4777       break;
4778   }
4779   if ((cache_info->debug != MagickFalse) &&
4780       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4781     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4782       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4783       nexus_info->region.width,(double) nexus_info->region.height,(double)
4784       nexus_info->region.x,(double) nexus_info->region.y);
4785   return(MagickTrue);
4786 }
4787 \f
4788 /*
4789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4790 %                                                                             %
4791 %                                                                             %
4792 %                                                                             %
4793 +   R e f e r e n c e P i x e l C a c h e                                     %
4794 %                                                                             %
4795 %                                                                             %
4796 %                                                                             %
4797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4798 %
4799 %  ReferencePixelCache() increments the reference count associated with the
4800 %  pixel cache returning a pointer to the cache.
4801 %
4802 %  The format of the ReferencePixelCache method is:
4803 %
4804 %      Cache ReferencePixelCache(Cache cache_info)
4805 %
4806 %  A description of each parameter follows:
4807 %
4808 %    o cache_info: the pixel cache.
4809 %
4810 */
4811 MagickExport Cache ReferencePixelCache(Cache cache)
4812 {
4813   CacheInfo
4814     *cache_info;
4815
4816   assert(cache != (Cache *) NULL);
4817   cache_info=(CacheInfo *) cache;
4818   assert(cache_info->signature == MagickSignature);
4819   LockSemaphoreInfo(cache_info->semaphore);
4820   cache_info->reference_count++;
4821   UnlockSemaphoreInfo(cache_info->semaphore);
4822   return(cache_info);
4823 }
4824 \f
4825 /*
4826 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4827 %                                                                             %
4828 %                                                                             %
4829 %                                                                             %
4830 +   S e t P i x e l C a c h e M e t h o d s                                   %
4831 %                                                                             %
4832 %                                                                             %
4833 %                                                                             %
4834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4835 %
4836 %  SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4837 %
4838 %  The format of the SetPixelCacheMethods() method is:
4839 %
4840 %      SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4841 %
4842 %  A description of each parameter follows:
4843 %
4844 %    o cache: the pixel cache.
4845 %
4846 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
4847 %
4848 */
4849 MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4850 {
4851   CacheInfo
4852     *cache_info;
4853
4854   GetOneAuthenticPixelFromHandler
4855     get_one_authentic_pixel_from_handler;
4856
4857   GetOneVirtualPixelFromHandler
4858     get_one_virtual_pixel_from_handler;
4859
4860   /*
4861     Set cache pixel methods.
4862   */
4863   assert(cache != (Cache) NULL);
4864   assert(cache_methods != (CacheMethods *) NULL);
4865   cache_info=(CacheInfo *) cache;
4866   assert(cache_info->signature == MagickSignature);
4867   if (cache_info->debug != MagickFalse)
4868     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4869       cache_info->filename);
4870   if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4871     cache_info->methods.get_virtual_pixel_handler=
4872       cache_methods->get_virtual_pixel_handler;
4873   if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4874     cache_info->methods.destroy_pixel_handler=
4875       cache_methods->destroy_pixel_handler;
4876   if (cache_methods->get_virtual_indexes_from_handler !=
4877       (GetVirtualIndexesFromHandler) NULL)
4878     cache_info->methods.get_virtual_indexes_from_handler=
4879       cache_methods->get_virtual_indexes_from_handler;
4880   if (cache_methods->get_authentic_pixels_handler !=
4881       (GetAuthenticPixelsHandler) NULL)
4882     cache_info->methods.get_authentic_pixels_handler=
4883       cache_methods->get_authentic_pixels_handler;
4884   if (cache_methods->queue_authentic_pixels_handler !=
4885       (QueueAuthenticPixelsHandler) NULL)
4886     cache_info->methods.queue_authentic_pixels_handler=
4887       cache_methods->queue_authentic_pixels_handler;
4888   if (cache_methods->sync_authentic_pixels_handler !=
4889       (SyncAuthenticPixelsHandler) NULL)
4890     cache_info->methods.sync_authentic_pixels_handler=
4891       cache_methods->sync_authentic_pixels_handler;
4892   if (cache_methods->get_authentic_pixels_from_handler !=
4893       (GetAuthenticPixelsFromHandler) NULL)
4894     cache_info->methods.get_authentic_pixels_from_handler=
4895       cache_methods->get_authentic_pixels_from_handler;
4896   if (cache_methods->get_authentic_indexes_from_handler !=
4897       (GetAuthenticIndexesFromHandler) NULL)
4898     cache_info->methods.get_authentic_indexes_from_handler=
4899       cache_methods->get_authentic_indexes_from_handler;
4900   get_one_virtual_pixel_from_handler=
4901     cache_info->methods.get_one_virtual_pixel_from_handler;
4902   if (get_one_virtual_pixel_from_handler !=
4903       (GetOneVirtualPixelFromHandler) NULL)
4904     cache_info->methods.get_one_virtual_pixel_from_handler=
4905       cache_methods->get_one_virtual_pixel_from_handler;
4906   get_one_authentic_pixel_from_handler=
4907     cache_methods->get_one_authentic_pixel_from_handler;
4908   if (get_one_authentic_pixel_from_handler !=
4909       (GetOneAuthenticPixelFromHandler) NULL)
4910     cache_info->methods.get_one_authentic_pixel_from_handler=
4911       cache_methods->get_one_authentic_pixel_from_handler;
4912 }
4913 \f
4914 /*
4915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4916 %                                                                             %
4917 %                                                                             %
4918 %                                                                             %
4919 +   S e t P i x e l C a c h e N e x u s P i x e l s                           %
4920 %                                                                             %
4921 %                                                                             %
4922 %                                                                             %
4923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4924 %
4925 %  SetPixelCacheNexusPixels() defines the region of the cache for the
4926 %  specified cache nexus.
4927 %
4928 %  The format of the SetPixelCacheNexusPixels() method is:
4929 %
4930 %      PixelPacket SetPixelCacheNexusPixels(const Image *image,
4931 %        const RectangleInfo *region,NexusInfo *nexus_info,
4932 %        ExceptionInfo *exception)
4933 %
4934 %  A description of each parameter follows:
4935 %
4936 %    o image: the image.
4937 %
4938 %    o region: A pointer to the RectangleInfo structure that defines the
4939 %      region of this particular cache nexus.
4940 %
4941 %    o nexus_info: the cache nexus to set.
4942 %
4943 %    o exception: return any errors or warnings in this structure.
4944 %
4945 */
4946
4947 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4948   NexusInfo *nexus_info,ExceptionInfo *exception)
4949 {
4950   if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4951     return(MagickFalse);
4952   nexus_info->mapped=MagickFalse;
4953   nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4954     nexus_info->length);
4955   if (nexus_info->cache == (PixelPacket *) NULL)
4956     {
4957       nexus_info->mapped=MagickTrue;
4958       nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4959         nexus_info->length);
4960     }
4961   if (nexus_info->cache == (PixelPacket *) NULL)
4962     {
4963       (void) ThrowMagickException(exception,GetMagickModule(),
4964         ResourceLimitError,"MemoryAllocationFailed","`%s'",
4965         cache_info->filename);
4966       return(MagickFalse);
4967     }
4968   return(MagickTrue);
4969 }
4970
4971 static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4972   const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4973 {
4974   CacheInfo
4975     *cache_info;
4976
4977   MagickBooleanType
4978     status;
4979
4980   MagickSizeType
4981     length,
4982     number_pixels;
4983
4984   cache_info=(CacheInfo *) image->cache;
4985   assert(cache_info->signature == MagickSignature);
4986   if (cache_info->type == UndefinedCache)
4987     return((PixelPacket *) NULL);
4988   nexus_info->region=(*region);
4989   if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4990       (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
4991     {
4992       ssize_t
4993         x,
4994         y;
4995
4996       x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4997       y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4998       if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4999            (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5000           ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5001            ((nexus_info->region.width == cache_info->columns) ||
5002             ((nexus_info->region.width % cache_info->columns) == 0)))))
5003         {
5004           MagickOffsetType
5005             offset;
5006
5007           /*
5008             Pixels are accessed directly from memory.
5009           */
5010           offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5011             nexus_info->region.x;
5012           nexus_info->pixels=cache_info->pixels+offset;
5013           nexus_info->indexes=(IndexPacket *) NULL;
5014           if (cache_info->active_index_channel != MagickFalse)
5015             nexus_info->indexes=cache_info->indexes+offset;
5016           return(nexus_info->pixels);
5017         }
5018     }
5019   /*
5020     Pixels are stored in a cache region until they are synced to the cache.
5021   */
5022   number_pixels=(MagickSizeType) nexus_info->region.width*
5023     nexus_info->region.height;
5024   length=number_pixels*sizeof(PixelPacket);
5025   if (cache_info->active_index_channel != MagickFalse)
5026     length+=number_pixels*sizeof(IndexPacket);
5027   if (nexus_info->cache == (PixelPacket *) NULL)
5028     {
5029       nexus_info->length=length;
5030       status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5031       if (status == MagickFalse)
5032         {
5033           nexus_info->length=0;
5034           return((PixelPacket *) NULL);
5035         }
5036     }
5037   else
5038     if (nexus_info->length != length)
5039       {
5040         RelinquishCacheNexusPixels(nexus_info);
5041         nexus_info->length=length;
5042         status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5043         if (status == MagickFalse)
5044           {
5045             nexus_info->length=0;
5046             return((PixelPacket *) NULL);
5047           }
5048       }
5049   nexus_info->pixels=nexus_info->cache;
5050   nexus_info->indexes=(IndexPacket *) NULL;
5051   if (cache_info->active_index_channel != MagickFalse)
5052     nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5053   return(nexus_info->pixels);
5054 }
5055 \f
5056 /*
5057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5058 %                                                                             %
5059 %                                                                             %
5060 %                                                                             %
5061 %   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                       %
5062 %                                                                             %
5063 %                                                                             %
5064 %                                                                             %
5065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5066 %
5067 %  SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5068 %  pixel cache and returns the previous setting.  A virtual pixel is any pixel
5069 %  access that is outside the boundaries of the image cache.
5070 %
5071 %  The format of the SetPixelCacheVirtualMethod() method is:
5072 %
5073 %      VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5074 %        const VirtualPixelMethod virtual_pixel_method)
5075 %
5076 %  A description of each parameter follows:
5077 %
5078 %    o image: the image.
5079 %
5080 %    o virtual_pixel_method: choose the type of virtual pixel.
5081 %
5082 */
5083 MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5084   const VirtualPixelMethod virtual_pixel_method)
5085 {
5086   CacheInfo
5087     *cache_info;
5088
5089   VirtualPixelMethod
5090     method;
5091
5092   assert(image != (Image *) NULL);
5093   assert(image->signature == MagickSignature);
5094   if (image->debug != MagickFalse)
5095     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5096   assert(image->cache != (Cache) NULL);
5097   cache_info=(CacheInfo *) image->cache;
5098   assert(cache_info->signature == MagickSignature);
5099   method=cache_info->virtual_pixel_method;
5100   cache_info->virtual_pixel_method=virtual_pixel_method;
5101   return(method);
5102 }
5103 \f
5104 /*
5105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5106 %                                                                             %
5107 %                                                                             %
5108 %                                                                             %
5109 +   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                   %
5110 %                                                                             %
5111 %                                                                             %
5112 %                                                                             %
5113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5114 %
5115 %  SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5116 %  in-memory or disk cache.  The method returns MagickTrue if the pixel region
5117 %  is synced, otherwise MagickFalse.
5118 %
5119 %  The format of the SyncAuthenticPixelCacheNexus() method is:
5120 %
5121 %      MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5122 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5123 %
5124 %  A description of each parameter follows:
5125 %
5126 %    o image: the image.
5127 %
5128 %    o nexus_info: the cache nexus to sync.
5129 %
5130 %    o exception: return any errors or warnings in this structure.
5131 %
5132 */
5133 MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5134   NexusInfo *nexus_info,ExceptionInfo *exception)
5135 {
5136   CacheInfo
5137     *cache_info;
5138
5139   MagickBooleanType
5140     status;
5141
5142   /*
5143     Transfer pixels to the cache.
5144   */
5145   assert(image != (Image *) NULL);
5146   assert(image->signature == MagickSignature);
5147   if (image->cache == (Cache) NULL)
5148     ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5149   cache_info=(CacheInfo *) image->cache;
5150   assert(cache_info->signature == MagickSignature);
5151   if (cache_info->type == UndefinedCache)
5152     return(MagickFalse);
5153   if ((image->clip_mask != (Image *) NULL) &&
5154       (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5155     return(MagickFalse);
5156   if ((image->mask != (Image *) NULL) &&
5157       (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5158     return(MagickFalse);
5159   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5160     return(MagickTrue);
5161   assert(cache_info->signature == MagickSignature);
5162   status=WritePixelCachePixels(cache_info,nexus_info,exception);
5163   if ((cache_info->active_index_channel != MagickFalse) &&
5164       (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5165     return(MagickFalse);
5166   return(status);
5167 }
5168 \f
5169 /*
5170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5171 %                                                                             %
5172 %                                                                             %
5173 %                                                                             %
5174 +   S y n c A u t h e n t i c P i x e l C a c h e                             %
5175 %                                                                             %
5176 %                                                                             %
5177 %                                                                             %
5178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5179 %
5180 %  SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5181 %  or disk cache.  The method returns MagickTrue if the pixel region is synced,
5182 %  otherwise MagickFalse.
5183 %
5184 %  The format of the SyncAuthenticPixelsCache() method is:
5185 %
5186 %      MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5187 %        ExceptionInfo *exception)
5188 %
5189 %  A description of each parameter follows:
5190 %
5191 %    o image: the image.
5192 %
5193 %    o exception: return any errors or warnings in this structure.
5194 %
5195 */
5196 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5197   ExceptionInfo *exception)
5198 {
5199   CacheInfo
5200     *cache_info;
5201
5202   const int
5203     id = GetOpenMPThreadId();
5204
5205   assert(image != (Image *) NULL);
5206   assert(image->signature == MagickSignature);
5207   assert(image->cache != (Cache) NULL);
5208   cache_info=(CacheInfo *) image->cache;
5209   assert(cache_info->signature == MagickSignature);
5210   assert(id < (int) cache_info->number_threads);
5211   return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5212     exception));
5213 }
5214 \f
5215 /*
5216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5217 %                                                                             %
5218 %                                                                             %
5219 %                                                                             %
5220 %   S y n c A u t h e n t i c P i x e l s                                     %
5221 %                                                                             %
5222 %                                                                             %
5223 %                                                                             %
5224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5225 %
5226 %  SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5227 %  The method returns MagickTrue if the pixel region is flushed, otherwise
5228 %  MagickFalse.
5229 %
5230 %  The format of the SyncAuthenticPixels() method is:
5231 %
5232 %      MagickBooleanType SyncAuthenticPixels(Image *image,
5233 %        ExceptionInfo *exception)
5234 %
5235 %  A description of each parameter follows:
5236 %
5237 %    o image: the image.
5238 %
5239 %    o exception: return any errors or warnings in this structure.
5240 %
5241 */
5242 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5243   ExceptionInfo *exception)
5244 {
5245   CacheInfo
5246     *cache_info;
5247
5248   const int
5249     id = GetOpenMPThreadId();
5250
5251   assert(image != (Image *) NULL);
5252   assert(image->signature == MagickSignature);
5253   assert(image->cache != (Cache) NULL);
5254   cache_info=(CacheInfo *) image->cache;
5255   assert(cache_info->signature == MagickSignature);
5256   if (cache_info->methods.sync_authentic_pixels_handler !=
5257        (SyncAuthenticPixelsHandler) NULL)
5258     return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5259   assert(id < (int) cache_info->number_threads);
5260   return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5261     exception));
5262 }
5263 \f
5264 /*
5265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5266 %                                                                             %
5267 %                                                                             %
5268 %                                                                             %
5269 +   W r i t e P i x e l C a c h e I n d e x e s                               %
5270 %                                                                             %
5271 %                                                                             %
5272 %                                                                             %
5273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5274 %
5275 %  WritePixelCacheIndexes() writes the colormap indexes to the specified
5276 %  region of the pixel cache.
5277 %
5278 %  The format of the WritePixelCacheIndexes() method is:
5279 %
5280 %      MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5281 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5282 %
5283 %  A description of each parameter follows:
5284 %
5285 %    o cache_info: the pixel cache.
5286 %
5287 %    o nexus_info: the cache nexus to write the colormap indexes.
5288 %
5289 %    o exception: return any errors or warnings in this structure.
5290 %
5291 */
5292 static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5293   NexusInfo *nexus_info,ExceptionInfo *exception)
5294 {
5295   MagickOffsetType
5296     count,
5297     offset;
5298
5299   MagickSizeType
5300     extent,
5301     length;
5302
5303   register const IndexPacket
5304     *restrict p;
5305
5306   register ssize_t
5307     y;
5308
5309   size_t
5310     rows;
5311
5312   if (cache_info->active_index_channel == MagickFalse)
5313     return(MagickFalse);
5314   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5315     return(MagickTrue);
5316   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5317     nexus_info->region.x;
5318   length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5319   rows=nexus_info->region.height;
5320   extent=(MagickSizeType) length*rows;
5321   p=nexus_info->indexes;
5322   switch (cache_info->type)
5323   {
5324     case MemoryCache:
5325     case MapCache:
5326     {
5327       register IndexPacket
5328         *restrict q;
5329
5330       /*
5331         Write indexes to memory.
5332       */
5333       if ((cache_info->columns == nexus_info->region.width) &&
5334           (extent == (MagickSizeType) ((size_t) extent)))
5335         {
5336           length=extent;
5337           rows=1UL;
5338         }
5339       q=cache_info->indexes+offset;
5340       for (y=0; y < (ssize_t) rows; y++)
5341       {
5342         (void) memcpy(q,p,(size_t) length);
5343         p+=nexus_info->region.width;
5344         q+=cache_info->columns;
5345       }
5346       break;
5347     }
5348     case DiskCache:
5349     {
5350       /*
5351         Write indexes to disk.
5352       */
5353       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5354         {
5355           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5356             cache_info->cache_filename);
5357           return(MagickFalse);
5358         }
5359       if ((cache_info->columns == nexus_info->region.width) &&
5360           (extent <= MagickMaxBufferExtent))
5361         {
5362           length=extent;
5363           rows=1UL;
5364         }
5365       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5366       for (y=0; y < (ssize_t) rows; y++)
5367       {
5368         count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5369           sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5370           p);
5371         if ((MagickSizeType) count < length)
5372           break;
5373         p+=nexus_info->region.width;
5374         offset+=cache_info->columns;
5375       }
5376       if (y < (ssize_t) rows)
5377         {
5378           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5379             cache_info->cache_filename);
5380           return(MagickFalse);
5381         }
5382       break;
5383     }
5384     default:
5385       break;
5386   }
5387   if ((cache_info->debug != MagickFalse) &&
5388       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5389     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5390       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5391       nexus_info->region.width,(double) nexus_info->region.height,(double)
5392       nexus_info->region.x,(double) nexus_info->region.y);
5393   return(MagickTrue);
5394 }
5395 \f
5396 /*
5397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5398 %                                                                             %
5399 %                                                                             %
5400 %                                                                             %
5401 +   W r i t e C a c h e P i x e l s                                           %
5402 %                                                                             %
5403 %                                                                             %
5404 %                                                                             %
5405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5406 %
5407 %  WritePixelCachePixels() writes image pixels to the specified region of the
5408 %  pixel cache.
5409 %
5410 %  The format of the WritePixelCachePixels() method is:
5411 %
5412 %      MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5413 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5414 %
5415 %  A description of each parameter follows:
5416 %
5417 %    o cache_info: the pixel cache.
5418 %
5419 %    o nexus_info: the cache nexus to write the pixels.
5420 %
5421 %    o exception: return any errors or warnings in this structure.
5422 %
5423 */
5424 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5425   NexusInfo *nexus_info,ExceptionInfo *exception)
5426 {
5427   MagickOffsetType
5428     count,
5429     offset;
5430
5431   MagickSizeType
5432     extent,
5433     length;
5434
5435   register const PixelPacket
5436     *restrict p;
5437
5438   register ssize_t
5439     y;
5440
5441   size_t
5442     rows;
5443
5444   if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5445     return(MagickTrue);
5446   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5447     nexus_info->region.x;
5448   length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5449   rows=nexus_info->region.height;
5450   extent=length*rows;
5451   p=nexus_info->pixels;
5452   switch (cache_info->type)
5453   {
5454     case MemoryCache:
5455     case MapCache:
5456     {
5457       register PixelPacket
5458         *restrict q;
5459
5460       /*
5461         Write pixels to memory.
5462       */
5463       if ((cache_info->columns == nexus_info->region.width) &&
5464           (extent == (MagickSizeType) ((size_t) extent)))
5465         {
5466           length=extent;
5467           rows=1UL;
5468         }
5469       q=cache_info->pixels+offset;
5470       for (y=0; y < (ssize_t) rows; y++)
5471       {
5472         (void) memcpy(q,p,(size_t) length);
5473         p+=nexus_info->region.width;
5474         q+=cache_info->columns;
5475       }
5476       break;
5477     }
5478     case DiskCache:
5479     {
5480       /*
5481         Write pixels to disk.
5482       */
5483       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5484         {
5485           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5486             cache_info->cache_filename);
5487           return(MagickFalse);
5488         }
5489       if ((cache_info->columns == nexus_info->region.width) &&
5490           (extent <= MagickMaxBufferExtent))
5491         {
5492           length=extent;
5493           rows=1UL;
5494         }
5495       for (y=0; y < (ssize_t) rows; y++)
5496       {
5497         count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5498           sizeof(*p),length,(const unsigned char *) p);
5499         if ((MagickSizeType) count < length)
5500           break;
5501         p+=nexus_info->region.width;
5502         offset+=cache_info->columns;
5503       }
5504       if (y < (ssize_t) rows)
5505         {
5506           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5507             cache_info->cache_filename);
5508           return(MagickFalse);
5509         }
5510       break;
5511     }
5512     default:
5513       break;
5514   }
5515   if ((cache_info->debug != MagickFalse) &&
5516       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5517     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5518       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5519       nexus_info->region.width,(double) nexus_info->region.height,(double)
5520       nexus_info->region.x,(double) nexus_info->region.y);
5521   return(MagickTrue);
5522 }