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