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