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