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