]> 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,MagickTrue,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[BlackPixelChannel]=image->background_color.black;
2151       pixel[AlphaPixelChannel]=image->background_color.alpha;
2152       return(MagickFalse);
2153     }
2154   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2155   {
2156     PixelChannel
2157       channel;
2158
2159     channel=GetPixelChannelMapChannel(image,i);
2160     pixel[channel]=q[i];
2161   }
2162   return(MagickTrue);
2163 }
2164 \f
2165 /*
2166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2167 %                                                                             %
2168 %                                                                             %
2169 %                                                                             %
2170 +   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                 %
2171 %                                                                             %
2172 %                                                                             %
2173 %                                                                             %
2174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2175 %
2176 %  GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2177 %  location.  The image background color is returned if an error occurs.
2178 %
2179 %  The format of the GetOneAuthenticPixelFromCache() method is:
2180 %
2181 %      MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2182 %        const ssize_t x,const ssize_t y,Quantum *pixel,
2183 %        ExceptionInfo *exception)
2184 %
2185 %  A description of each parameter follows:
2186 %
2187 %    o image: the image.
2188 %
2189 %    o x,y:  These values define the location of the pixel to return.
2190 %
2191 %    o pixel: return a pixel at the specified (x,y) location.
2192 %
2193 %    o exception: return any errors or warnings in this structure.
2194 %
2195 */
2196 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2197   const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2198 {
2199   CacheInfo
2200     *cache_info;
2201
2202   const int
2203     id = GetOpenMPThreadId();
2204
2205   register Quantum
2206     *q;
2207
2208   register ssize_t
2209     i;
2210
2211   assert(image != (const Image *) NULL);
2212   assert(image->signature == MagickSignature);
2213   assert(image->cache != (Cache) NULL);
2214   cache_info=(CacheInfo *) image->cache;
2215   assert(cache_info->signature == MagickSignature);
2216   assert(id < (int) cache_info->number_threads);
2217   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2218   q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2219     exception);
2220   if (q == (Quantum *) NULL)
2221     {
2222       pixel[RedPixelChannel]=image->background_color.red;
2223       pixel[GreenPixelChannel]=image->background_color.green;
2224       pixel[BluePixelChannel]=image->background_color.blue;
2225       pixel[BlackPixelChannel]=image->background_color.black;
2226       pixel[AlphaPixelChannel]=image->background_color.alpha;
2227       return(MagickFalse);
2228     }
2229   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2230   {
2231     PixelChannel
2232       channel;
2233
2234     channel=GetPixelChannelMapChannel(image,i);
2235     pixel[channel]=q[i];
2236   }
2237   return(MagickTrue);
2238 }
2239 \f
2240 /*
2241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242 %                                                                             %
2243 %                                                                             %
2244 %                                                                             %
2245 %   G e t O n e V i r t u a l M a g i c k P i x e l                           %
2246 %                                                                             %
2247 %                                                                             %
2248 %                                                                             %
2249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2250 %
2251 %  GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2252 %  location.  The image background color is returned if an error occurs.  If
2253 %  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2254 %
2255 %  The format of the GetOneVirtualMagickPixel() method is:
2256 %
2257 %      MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2258 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2259 %        const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2260 %
2261 %  A description of each parameter follows:
2262 %
2263 %    o image: the image.
2264 %
2265 %    o virtual_pixel_method: the virtual pixel method.
2266 %
2267 %    o x,y:  these values define the location of the pixel to return.
2268 %
2269 %    o pixel: return a pixel at the specified (x,y) location.
2270 %
2271 %    o exception: return any errors or warnings in this structure.
2272 %
2273 */
2274 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2275   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2276   PixelInfo *pixel,ExceptionInfo *exception)
2277 {
2278   CacheInfo
2279     *cache_info;
2280
2281   const int
2282     id = GetOpenMPThreadId();
2283
2284   register const Quantum
2285     *p;
2286
2287   assert(image != (const Image *) NULL);
2288   assert(image->signature == MagickSignature);
2289   assert(image->cache != (Cache) NULL);
2290   cache_info=(CacheInfo *) image->cache;
2291   assert(cache_info->signature == MagickSignature);
2292   assert(id < (int) cache_info->number_threads);
2293   p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2294     cache_info->nexus_info[id],exception);
2295   GetPixelInfo(image,pixel);
2296   if (p == (const Quantum *) NULL)
2297     return(MagickFalse);
2298   GetPixelInfoPixel(image,p,pixel);
2299   return(MagickTrue);
2300 }
2301 \f
2302 /*
2303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2304 %                                                                             %
2305 %                                                                             %
2306 %                                                                             %
2307 %   G e t O n e V i r t u a l P i x e l                                       %
2308 %                                                                             %
2309 %                                                                             %
2310 %                                                                             %
2311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2312 %
2313 %  GetOneVirtualPixel() returns a single virtual pixel at the specified
2314 %  (x,y) location.  The image background color is returned if an error occurs.
2315 %  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2316 %
2317 %  The format of the GetOneVirtualPixel() method is:
2318 %
2319 %      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2320 %        const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2321 %
2322 %  A description of each parameter follows:
2323 %
2324 %    o image: the image.
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 GetOneVirtualPixel(const Image *image,
2334   const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2335 {
2336   CacheInfo
2337     *cache_info;
2338
2339   const int
2340     id = GetOpenMPThreadId();
2341
2342   const Quantum
2343     *p;
2344
2345   register ssize_t
2346     i;
2347
2348   assert(image != (const Image *) NULL);
2349   assert(image->signature == MagickSignature);
2350   assert(image->cache != (Cache) NULL);
2351   cache_info=(CacheInfo *) image->cache;
2352   assert(cache_info->signature == MagickSignature);
2353   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2354   if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2355        (GetOneVirtualPixelFromHandler) NULL)
2356     return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2357       GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2358   assert(id < (int) cache_info->number_threads);
2359   p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2360     1UL,1UL,cache_info->nexus_info[id],exception);
2361   if (p == (const Quantum *) NULL)
2362     {
2363       pixel[RedPixelChannel]=image->background_color.red;
2364       pixel[GreenPixelChannel]=image->background_color.green;
2365       pixel[BluePixelChannel]=image->background_color.blue;
2366       pixel[BlackPixelChannel]=image->background_color.black;
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,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 F r o m C a c h e                     %
2387 %                                                                             %
2388 %                                                                             %
2389 %                                                                             %
2390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2391 %
2392 %  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2393 %  specified (x,y) location.  The image background color is returned if an
2394 %  error occurs.
2395 %
2396 %  The format of the GetOneVirtualPixelFromCache() method is:
2397 %
2398 %      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2399 %        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2400 %        Quantum *pixel,ExceptionInfo *exception)
2401 %
2402 %  A description of each parameter follows:
2403 %
2404 %    o image: the image.
2405 %
2406 %    o virtual_pixel_method: the virtual pixel method.
2407 %
2408 %    o x,y:  These values define the location of the pixel to return.
2409 %
2410 %    o pixel: return a pixel at the specified (x,y) location.
2411 %
2412 %    o exception: return any errors or warnings in this structure.
2413 %
2414 */
2415 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2416   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2417   Quantum *pixel,ExceptionInfo *exception)
2418 {
2419   CacheInfo
2420     *cache_info;
2421
2422   const int
2423     id = GetOpenMPThreadId();
2424
2425   const Quantum
2426     *p;
2427
2428   register ssize_t
2429     i;
2430
2431   assert(image != (const Image *) NULL);
2432   assert(image->signature == MagickSignature);
2433   assert(image->cache != (Cache) NULL);
2434   cache_info=(CacheInfo *) image->cache;
2435   assert(cache_info->signature == MagickSignature);
2436   assert(id < (int) cache_info->number_threads);
2437   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2438   p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2439     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[BlackPixelChannel]=image->background_color.black;
2446       pixel[AlphaPixelChannel]=image->background_color.alpha;
2447       return(MagickFalse);
2448     }
2449   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2450   {
2451     PixelChannel
2452       channel;
2453
2454     channel=GetPixelChannelMapChannel(image,i);
2455     pixel[channel]=p[i];
2456   }
2457   return(MagickTrue);
2458 }
2459 \f
2460 /*
2461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462 %                                                                             %
2463 %                                                                             %
2464 %                                                                             %
2465 +   G e t P i x e l C a c h e C o l o r s p a c e                             %
2466 %                                                                             %
2467 %                                                                             %
2468 %                                                                             %
2469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2470 %
2471 %  GetPixelCacheColorspace() returns the class type of the pixel cache.
2472 %
2473 %  The format of the GetPixelCacheColorspace() method is:
2474 %
2475 %      Colorspace GetPixelCacheColorspace(Cache cache)
2476 %
2477 %  A description of each parameter follows:
2478 %
2479 %    o cache: the pixel cache.
2480 %
2481 */
2482 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2483 {
2484   CacheInfo
2485     *cache_info;
2486
2487   assert(cache != (Cache) NULL);
2488   cache_info=(CacheInfo *) cache;
2489   assert(cache_info->signature == MagickSignature);
2490   if (cache_info->debug != MagickFalse)
2491     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2492       cache_info->filename);
2493   return(cache_info->colorspace);
2494 }
2495 \f
2496 /*
2497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2498 %                                                                             %
2499 %                                                                             %
2500 %                                                                             %
2501 +   G e t P i x e l C a c h e M e t h o d s                                   %
2502 %                                                                             %
2503 %                                                                             %
2504 %                                                                             %
2505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2506 %
2507 %  GetPixelCacheMethods() initializes the CacheMethods structure.
2508 %
2509 %  The format of the GetPixelCacheMethods() method is:
2510 %
2511 %      void GetPixelCacheMethods(CacheMethods *cache_methods)
2512 %
2513 %  A description of each parameter follows:
2514 %
2515 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
2516 %
2517 */
2518 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2519 {
2520   assert(cache_methods != (CacheMethods *) NULL);
2521   (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2522   cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2523   cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2524   cache_methods->get_virtual_metacontent_from_handler=
2525     GetVirtualMetacontentFromCache;
2526   cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2527   cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2528   cache_methods->get_authentic_metacontent_from_handler=
2529     GetAuthenticMetacontentFromCache;
2530   cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2531   cache_methods->get_one_authentic_pixel_from_handler=
2532     GetOneAuthenticPixelFromCache;
2533   cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2534   cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2535   cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2536 }
2537 \f
2538 /*
2539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2540 %                                                                             %
2541 %                                                                             %
2542 %                                                                             %
2543 +   G e t P i x e l C a c h e N e x u s E x t e n t                           %
2544 %                                                                             %
2545 %                                                                             %
2546 %                                                                             %
2547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2548 %
2549 %  GetPixelCacheNexusExtent() returns the extent of the pixels associated
2550 %  corresponding with the last call to SetPixelCacheNexusPixels() or
2551 %  GetPixelCacheNexusPixels().
2552 %
2553 %  The format of the GetPixelCacheNexusExtent() method is:
2554 %
2555 %      MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2556 %        NexusInfo *nexus_info)
2557 %
2558 %  A description of each parameter follows:
2559 %
2560 %    o nexus_info: the nexus info.
2561 %
2562 */
2563 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2564   NexusInfo *nexus_info)
2565 {
2566   CacheInfo
2567     *cache_info;
2568
2569   MagickSizeType
2570     extent;
2571
2572   assert(cache != NULL);
2573   cache_info=(CacheInfo *) cache;
2574   assert(cache_info->signature == MagickSignature);
2575   extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2576   if (extent == 0)
2577     return((MagickSizeType) cache_info->columns*cache_info->rows);
2578   return(extent);
2579 }
2580 \f
2581 /*
2582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2583 %                                                                             %
2584 %                                                                             %
2585 %                                                                             %
2586 +   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                 %
2587 %                                                                             %
2588 %                                                                             %
2589 %                                                                             %
2590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591 %
2592 %  GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2593 %  cache nexus.
2594 %
2595 %  The format of the GetPixelCacheNexusMetacontent() method is:
2596 %
2597 %      void *GetPixelCacheNexusMetacontent(const Cache cache,
2598 %        NexusInfo *nexus_info)
2599 %
2600 %  A description of each parameter follows:
2601 %
2602 %    o cache: the pixel cache.
2603 %
2604 %    o nexus_info: the cache nexus to return the meta-content.
2605 %
2606 */
2607 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2608   NexusInfo *nexus_info)
2609 {
2610   CacheInfo
2611     *cache_info;
2612
2613   assert(cache != NULL);
2614   cache_info=(CacheInfo *) cache;
2615   assert(cache_info->signature == MagickSignature);
2616   if (cache_info->storage_class == UndefinedClass)
2617     return((void *) NULL);
2618   return(nexus_info->metacontent);
2619 }
2620 \f
2621 /*
2622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2623 %                                                                             %
2624 %                                                                             %
2625 %                                                                             %
2626 +   G e t P i x e l C a c h e N e x u s P i x e l s                           %
2627 %                                                                             %
2628 %                                                                             %
2629 %                                                                             %
2630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2631 %
2632 %  GetPixelCacheNexusPixels() returns the pixels associated with the specified
2633 %  cache nexus.
2634 %
2635 %  The format of the GetPixelCacheNexusPixels() method is:
2636 %
2637 %      Quantum *GetPixelCacheNexusPixels(const Cache cache,
2638 %        NexusInfo *nexus_info)
2639 %
2640 %  A description of each parameter follows:
2641 %
2642 %    o cache: the pixel cache.
2643 %
2644 %    o nexus_info: the cache nexus to return the pixels.
2645 %
2646 */
2647 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2648   NexusInfo *nexus_info)
2649 {
2650   CacheInfo
2651     *cache_info;
2652
2653   assert(cache != NULL);
2654   cache_info=(CacheInfo *) cache;
2655   assert(cache_info->signature == MagickSignature);
2656   if (cache_info->storage_class == UndefinedClass)
2657     return((Quantum *) NULL);
2658   return(nexus_info->pixels);
2659 }
2660 \f
2661 /*
2662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2663 %                                                                             %
2664 %                                                                             %
2665 %                                                                             %
2666 +   G e t P i x e l C a c h e P i x e l s                                     %
2667 %                                                                             %
2668 %                                                                             %
2669 %                                                                             %
2670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2671 %
2672 %  GetPixelCachePixels() returns the pixels associated with the specified image.
2673 %
2674 %  The format of the GetPixelCachePixels() method is:
2675 %
2676 %      void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2677 %        ExceptionInfo *exception)
2678 %
2679 %  A description of each parameter follows:
2680 %
2681 %    o image: the image.
2682 %
2683 %    o length: the pixel cache length.
2684 %
2685 %    o exception: return any errors or warnings in this structure.
2686 %
2687 */
2688 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2689   ExceptionInfo *exception)
2690 {
2691   CacheInfo
2692     *cache_info;
2693
2694   assert(image != (const Image *) NULL);
2695   assert(image->signature == MagickSignature);
2696   assert(image->cache != (Cache) NULL);
2697   assert(length != (MagickSizeType *) NULL);
2698   assert(exception != (ExceptionInfo *) NULL);
2699   assert(exception->signature == MagickSignature);
2700   cache_info=(CacheInfo *) image->cache;
2701   assert(cache_info->signature == MagickSignature);
2702   *length=0;
2703   if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2704     return((void *) NULL);
2705   *length=cache_info->length;
2706   return((void *) cache_info->pixels);
2707 }
2708 \f
2709 /*
2710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2711 %                                                                             %
2712 %                                                                             %
2713 %                                                                             %
2714 +   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                         %
2715 %                                                                             %
2716 %                                                                             %
2717 %                                                                             %
2718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719 %
2720 %  GetPixelCacheStorageClass() returns the class type of the pixel cache.
2721 %
2722 %  The format of the GetPixelCacheStorageClass() method is:
2723 %
2724 %      ClassType GetPixelCacheStorageClass(Cache cache)
2725 %
2726 %  A description of each parameter follows:
2727 %
2728 %    o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2729 %
2730 %    o cache: the pixel cache.
2731 %
2732 */
2733 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2734 {
2735   CacheInfo
2736     *cache_info;
2737
2738   assert(cache != (Cache) NULL);
2739   cache_info=(CacheInfo *) cache;
2740   assert(cache_info->signature == MagickSignature);
2741   if (cache_info->debug != MagickFalse)
2742     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2743       cache_info->filename);
2744   return(cache_info->storage_class);
2745 }
2746 \f
2747 /*
2748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749 %                                                                             %
2750 %                                                                             %
2751 %                                                                             %
2752 +   G e t P i x e l C a c h e T i l e S i z e                                 %
2753 %                                                                             %
2754 %                                                                             %
2755 %                                                                             %
2756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757 %
2758 %  GetPixelCacheTileSize() returns the pixel cache tile size.
2759 %
2760 %  The format of the GetPixelCacheTileSize() method is:
2761 %
2762 %      void GetPixelCacheTileSize(const Image *image,size_t *width,
2763 %        size_t *height)
2764 %
2765 %  A description of each parameter follows:
2766 %
2767 %    o image: the image.
2768 %
2769 %    o width: the optimize cache tile width in pixels.
2770 %
2771 %    o height: the optimize cache tile height in pixels.
2772 %
2773 */
2774 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2775   size_t *height)
2776 {
2777   CacheInfo
2778     *cache_info;
2779
2780   assert(image != (Image *) NULL);
2781   assert(image->signature == MagickSignature);
2782   if (image->debug != MagickFalse)
2783     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2784   cache_info=(CacheInfo *) image->cache;
2785   assert(cache_info->signature == MagickSignature);
2786   *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2787   if (GetPixelCacheType(image) == DiskCache)
2788     *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2789   *height=(*width);
2790 }
2791 \f
2792 /*
2793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2794 %                                                                             %
2795 %                                                                             %
2796 %                                                                             %
2797 +   G e t P i x e l C a c h e T y p e                                         %
2798 %                                                                             %
2799 %                                                                             %
2800 %                                                                             %
2801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802 %
2803 %  GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2804 %
2805 %  The format of the GetPixelCacheType() method is:
2806 %
2807 %      CacheType GetPixelCacheType(const Image *image)
2808 %
2809 %  A description of each parameter follows:
2810 %
2811 %    o image: the image.
2812 %
2813 */
2814 MagickPrivate CacheType GetPixelCacheType(const Image *image)
2815 {
2816   CacheInfo
2817     *cache_info;
2818
2819   assert(image != (Image *) NULL);
2820   assert(image->signature == MagickSignature);
2821   assert(image->cache != (Cache) NULL);
2822   cache_info=(CacheInfo *) image->cache;
2823   assert(cache_info->signature == MagickSignature);
2824   return(cache_info->type);
2825 }
2826 \f
2827 /*
2828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2829 %                                                                             %
2830 %                                                                             %
2831 %                                                                             %
2832 +   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                       %
2833 %                                                                             %
2834 %                                                                             %
2835 %                                                                             %
2836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2837 %
2838 %  GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2839 %  pixel cache.  A virtual pixel is any pixel access that is outside the
2840 %  boundaries of the image cache.
2841 %
2842 %  The format of the GetPixelCacheVirtualMethod() method is:
2843 %
2844 %      VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2845 %
2846 %  A description of each parameter follows:
2847 %
2848 %    o image: the image.
2849 %
2850 */
2851 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2852 {
2853   CacheInfo
2854     *cache_info;
2855
2856   assert(image != (Image *) NULL);
2857   assert(image->signature == MagickSignature);
2858   assert(image->cache != (Cache) NULL);
2859   cache_info=(CacheInfo *) image->cache;
2860   assert(cache_info->signature == MagickSignature);
2861   return(cache_info->virtual_pixel_method);
2862 }
2863 \f
2864 /*
2865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2866 %                                                                             %
2867 %                                                                             %
2868 %                                                                             %
2869 +   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               %
2870 %                                                                             %
2871 %                                                                             %
2872 %                                                                             %
2873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2874 %
2875 %  GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2876 %  the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2877 %
2878 %  The format of the GetVirtualMetacontentFromCache() method is:
2879 %
2880 %      void *GetVirtualMetacontentFromCache(const Image *image)
2881 %
2882 %  A description of each parameter follows:
2883 %
2884 %    o image: the image.
2885 %
2886 */
2887 static const void *GetVirtualMetacontentFromCache(const Image *image)
2888 {
2889   CacheInfo
2890     *cache_info;
2891
2892   const int
2893     id = GetOpenMPThreadId();
2894
2895   const void
2896     *metacontent;
2897
2898   assert(image != (const Image *) NULL);
2899   assert(image->signature == MagickSignature);
2900   assert(image->cache != (Cache) NULL);
2901   cache_info=(CacheInfo *) image->cache;
2902   assert(cache_info->signature == MagickSignature);
2903   assert(id < (int) cache_info->number_threads);
2904   metacontent=GetVirtualMetacontentFromNexus(cache_info,
2905     cache_info->nexus_info[id]);
2906   return(metacontent);
2907 }
2908 \f
2909 /*
2910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2911 %                                                                             %
2912 %                                                                             %
2913 %                                                                             %
2914 +   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               %
2915 %                                                                             %
2916 %                                                                             %
2917 %                                                                             %
2918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2919 %
2920 %  GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2921 %  cache nexus.
2922 %
2923 %  The format of the GetVirtualMetacontentFromNexus() method is:
2924 %
2925 %      const void *GetVirtualMetacontentFromNexus(const Cache cache,
2926 %        NexusInfo *nexus_info)
2927 %
2928 %  A description of each parameter follows:
2929 %
2930 %    o cache: the pixel cache.
2931 %
2932 %    o nexus_info: the cache nexus to return the meta-content.
2933 %
2934 */
2935 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2936   NexusInfo *nexus_info)
2937 {
2938   CacheInfo
2939     *cache_info;
2940
2941   assert(cache != (Cache) NULL);
2942   cache_info=(CacheInfo *) cache;
2943   assert(cache_info->signature == MagickSignature);
2944   if (cache_info->storage_class == UndefinedClass)
2945     return((void *) NULL);
2946   return(nexus_info->metacontent);
2947 }
2948 \f
2949 /*
2950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2951 %                                                                             %
2952 %                                                                             %
2953 %                                                                             %
2954 %   G e t V i r t u a l M e t a c o n t e n t                                 %
2955 %                                                                             %
2956 %                                                                             %
2957 %                                                                             %
2958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2959 %
2960 %  GetVirtualMetacontent() returns the virtual metacontent corresponding with
2961 %  the last call to QueueAuthenticPixels() or GetVirtualPixels().  NULL is
2962 %  returned if the meta-content are not available.
2963 %
2964 %  The format of the GetVirtualMetacontent() method is:
2965 %
2966 %      const void *GetVirtualMetacontent(const Image *image)
2967 %
2968 %  A description of each parameter follows:
2969 %
2970 %    o image: the image.
2971 %
2972 */
2973 MagickExport const void *GetVirtualMetacontent(const Image *image)
2974 {
2975   CacheInfo
2976     *cache_info;
2977
2978   const int
2979     id = GetOpenMPThreadId();
2980
2981   const void
2982     *metacontent;
2983
2984   assert(image != (const Image *) NULL);
2985   assert(image->signature == MagickSignature);
2986   assert(image->cache != (Cache) NULL);
2987   cache_info=(CacheInfo *) image->cache;
2988   assert(cache_info->signature == MagickSignature);
2989   if (cache_info->methods.get_virtual_metacontent_from_handler !=
2990        (GetVirtualMetacontentFromHandler) NULL)
2991     {
2992       metacontent=cache_info->methods.
2993         get_virtual_metacontent_from_handler(image);
2994       return(metacontent);
2995     }
2996   assert(id < (int) cache_info->number_threads);
2997   metacontent=GetVirtualMetacontentFromNexus(cache_info,
2998     cache_info->nexus_info[id]);
2999   return(metacontent);
3000 }
3001 \f
3002 /*
3003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3004 %                                                                             %
3005 %                                                                             %
3006 %                                                                             %
3007 +   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                         %
3008 %                                                                             %
3009 %                                                                             %
3010 %                                                                             %
3011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3012 %
3013 %  GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3014 %  pixel cache as defined by the geometry parameters.   A pointer to the pixels
3015 %  is returned if the pixels are transferred, otherwise a NULL is returned.
3016 %
3017 %  The format of the GetVirtualPixelsFromNexus() method is:
3018 %
3019 %      Quantum *GetVirtualPixelsFromNexus(const Image *image,
3020 %        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3021 %        const size_t columns,const size_t rows,NexusInfo *nexus_info,
3022 %        ExceptionInfo *exception)
3023 %
3024 %  A description of each parameter follows:
3025 %
3026 %    o image: the image.
3027 %
3028 %    o virtual_pixel_method: the virtual pixel method.
3029 %
3030 %    o x,y,columns,rows:  These values define the perimeter of a region of
3031 %      pixels.
3032 %
3033 %    o nexus_info: the cache nexus to acquire.
3034 %
3035 %    o exception: return any errors or warnings in this structure.
3036 %
3037 */
3038
3039 static ssize_t
3040   DitherMatrix[64] =
3041   {
3042      0,  48,  12,  60,   3,  51,  15,  63,
3043     32,  16,  44,  28,  35,  19,  47,  31,
3044      8,  56,   4,  52,  11,  59,   7,  55,
3045     40,  24,  36,  20,  43,  27,  39,  23,
3046      2,  50,  14,  62,   1,  49,  13,  61,
3047     34,  18,  46,  30,  33,  17,  45,  29,
3048     10,  58,   6,  54,   9,  57,   5,  53,
3049     42,  26,  38,  22,  41,  25,  37,  21
3050   };
3051
3052 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3053 {
3054   ssize_t
3055     index;
3056
3057   index=x+DitherMatrix[x & 0x07]-32L;
3058   if (index < 0L)
3059     return(0L);
3060   if (index >= (ssize_t) columns)
3061     return((ssize_t) columns-1L);
3062   return(index);
3063 }
3064
3065 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3066 {
3067   ssize_t
3068     index;
3069
3070   index=y+DitherMatrix[y & 0x07]-32L;
3071   if (index < 0L)
3072     return(0L);
3073   if (index >= (ssize_t) rows)
3074     return((ssize_t) rows-1L);
3075   return(index);
3076 }
3077
3078 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3079 {
3080   if (x < 0L)
3081     return(0L);
3082   if (x >= (ssize_t) columns)
3083     return((ssize_t) (columns-1));
3084   return(x);
3085 }
3086
3087 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3088 {
3089   if (y < 0L)
3090     return(0L);
3091   if (y >= (ssize_t) rows)
3092     return((ssize_t) (rows-1));
3093   return(y);
3094 }
3095
3096 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3097 {
3098   return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3099 }
3100
3101 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3102 {
3103   return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3104 }
3105
3106 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3107   const size_t extent)
3108 {
3109   MagickModulo
3110     modulo;
3111
3112   /*
3113     Compute the remainder of dividing offset by extent.  It returns not only
3114     the quotient (tile the offset falls in) but also the positive remainer
3115     within that tile such that 0 <= remainder < extent.  This method is
3116     essentially a ldiv() using a floored modulo division rather than the
3117     normal default truncated modulo division.
3118   */
3119   modulo.quotient=offset/(ssize_t) extent;
3120   if (offset < 0L)
3121     modulo.quotient--;
3122   modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3123   return(modulo);
3124 }
3125
3126 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3127   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3128   const size_t columns,const size_t rows,NexusInfo *nexus_info,
3129   ExceptionInfo *exception)
3130 {
3131   CacheInfo
3132     *cache_info;
3133
3134   MagickOffsetType
3135     offset;
3136
3137   MagickSizeType
3138     length,
3139     number_pixels;
3140
3141   NexusInfo
3142     **virtual_nexus;
3143
3144   Quantum
3145     *pixels,
3146     virtual_pixel[CompositePixelChannel];
3147
3148   RectangleInfo
3149     region;
3150
3151   register const Quantum
3152     *restrict p;
3153
3154   register const void
3155     *restrict r;
3156
3157   register Quantum
3158     *restrict q;
3159
3160   register ssize_t
3161     i,
3162     u;
3163
3164   register unsigned char
3165     *restrict s;
3166
3167   ssize_t
3168     v;
3169
3170   void
3171     *virtual_metacontent;
3172
3173   /*
3174     Acquire pixels.
3175   */
3176   assert(image != (const Image *) NULL);
3177   assert(image->signature == MagickSignature);
3178   assert(image->cache != (Cache) NULL);
3179   cache_info=(CacheInfo *) image->cache;
3180   assert(cache_info->signature == MagickSignature);
3181   if (cache_info->type == UndefinedCache)
3182     return((const Quantum *) NULL);
3183   region.x=x;
3184   region.y=y;
3185   region.width=columns;
3186   region.height=rows;
3187   pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3188   if (pixels == (Quantum *) NULL)
3189     return((const Quantum *) NULL);
3190   q=pixels;
3191   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3192     nexus_info->region.x;
3193   length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3194     nexus_info->region.width-1L;
3195   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3196   if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3197     if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3198         (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3199       {
3200         MagickBooleanType
3201           status;
3202
3203         /*
3204           Pixel request is inside cache extents.
3205         */
3206         if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3207           return(q);
3208         status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3209         if (status == MagickFalse)
3210           return((const Quantum *) NULL);
3211         if (cache_info->metacontent_extent != 0)
3212           {
3213             status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3214             if (status == MagickFalse)
3215               return((const Quantum *) NULL);
3216           }
3217         return(q);
3218       }
3219   /*
3220     Pixel request is outside cache extents.
3221   */
3222   s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3223   virtual_nexus=AcquirePixelCacheNexus(1);
3224   if (virtual_nexus == (NexusInfo **) NULL)
3225     {
3226       if (virtual_nexus != (NexusInfo **) NULL)
3227         virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3228       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3229         "UnableToGetCacheNexus","`%s'",image->filename);
3230       return((const Quantum *) NULL);
3231     }
3232   (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3233     sizeof(*virtual_pixel));
3234   virtual_metacontent=(void *) NULL;
3235   switch (virtual_pixel_method)
3236   {
3237     case BackgroundVirtualPixelMethod:
3238     case BlackVirtualPixelMethod:
3239     case GrayVirtualPixelMethod:
3240     case TransparentVirtualPixelMethod:
3241     case MaskVirtualPixelMethod:
3242     case WhiteVirtualPixelMethod:
3243     case EdgeVirtualPixelMethod:
3244     case CheckerTileVirtualPixelMethod:
3245     case HorizontalTileVirtualPixelMethod:
3246     case VerticalTileVirtualPixelMethod:
3247     {
3248       if (cache_info->metacontent_extent != 0)
3249         {
3250           /*
3251             Acquire a metacontent buffer.
3252           */
3253           virtual_metacontent=(void *) AcquireQuantumMemory(1,
3254             cache_info->metacontent_extent);
3255           if (virtual_metacontent == (void *) NULL)
3256             {
3257               virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3258               (void) ThrowMagickException(exception,GetMagickModule(),
3259                 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3260               return((const Quantum *) NULL);
3261             }
3262           (void) ResetMagickMemory(virtual_metacontent,0,
3263             cache_info->metacontent_extent);
3264         }
3265       switch (virtual_pixel_method)
3266       {
3267         case BlackVirtualPixelMethod:
3268         {
3269           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3270             SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3271           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3272           break;
3273         }
3274         case GrayVirtualPixelMethod:
3275         {
3276           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3277             SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3278               virtual_pixel);
3279           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3280           break;
3281         }
3282         case TransparentVirtualPixelMethod:
3283         {
3284           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3285             SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3286           SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3287           break;
3288         }
3289         case MaskVirtualPixelMethod:
3290         case WhiteVirtualPixelMethod:
3291         {
3292           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3293             SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3294           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3295           break;
3296         }
3297         default:
3298         {
3299           SetPixelRed(image,image->background_color.red,virtual_pixel);
3300           SetPixelGreen(image,image->background_color.green,virtual_pixel);
3301           SetPixelBlue(image,image->background_color.blue,virtual_pixel);
3302           if (image->colorspace == CMYKColorspace)
3303             SetPixelBlack(image,image->background_color.black,virtual_pixel);
3304           SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3305           break;
3306         }
3307       }
3308       break;
3309     }
3310     default:
3311       break;
3312   }
3313   for (v=0; v < (ssize_t) rows; v++)
3314   {
3315     for (u=0; u < (ssize_t) columns; u+=length)
3316     {
3317       length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3318       if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3319           (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3320           (length == 0))
3321         {
3322           MagickModulo
3323             x_modulo,
3324             y_modulo;
3325
3326           /*
3327             Transfer a single pixel.
3328           */
3329           length=(MagickSizeType) 1;
3330           switch (virtual_pixel_method)
3331           {
3332             default:
3333             {
3334               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3335                 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3336                 1UL,1UL,*virtual_nexus,exception);
3337               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3338               break;
3339             }
3340             case RandomVirtualPixelMethod:
3341             {
3342               if (cache_info->random_info == (RandomInfo *) NULL)
3343                 cache_info->random_info=AcquireRandomInfo();
3344               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3345                 RandomX(cache_info->random_info,cache_info->columns),
3346                 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3347                 *virtual_nexus,exception);
3348               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3349               break;
3350             }
3351             case DitherVirtualPixelMethod:
3352             {
3353               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3354                 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3355                 1UL,1UL,*virtual_nexus,exception);
3356               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3357               break;
3358             }
3359             case TileVirtualPixelMethod:
3360             {
3361               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3362               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3363               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3364                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3365                 exception);
3366               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3367               break;
3368             }
3369             case MirrorVirtualPixelMethod:
3370             {
3371               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3372               if ((x_modulo.quotient & 0x01) == 1L)
3373                 x_modulo.remainder=(ssize_t) cache_info->columns-
3374                   x_modulo.remainder-1L;
3375               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3376               if ((y_modulo.quotient & 0x01) == 1L)
3377                 y_modulo.remainder=(ssize_t) cache_info->rows-
3378                   y_modulo.remainder-1L;
3379               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3380                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3381                 exception);
3382               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3383               break;
3384             }
3385             case HorizontalTileEdgeVirtualPixelMethod:
3386             {
3387               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3388               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3389                 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3390                 *virtual_nexus,exception);
3391               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3392               break;
3393             }
3394             case VerticalTileEdgeVirtualPixelMethod:
3395             {
3396               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3397               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3398                 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3399                 *virtual_nexus,exception);
3400               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3401               break;
3402             }
3403             case BackgroundVirtualPixelMethod:
3404             case BlackVirtualPixelMethod:
3405             case GrayVirtualPixelMethod:
3406             case TransparentVirtualPixelMethod:
3407             case MaskVirtualPixelMethod:
3408             case WhiteVirtualPixelMethod:
3409             {
3410               p=virtual_pixel;
3411               r=virtual_metacontent;
3412               break;
3413             }
3414             case EdgeVirtualPixelMethod:
3415             case CheckerTileVirtualPixelMethod:
3416             {
3417               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3418               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3419               if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3420                 {
3421                   p=virtual_pixel;
3422                   r=virtual_metacontent;
3423                   break;
3424                 }
3425               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3426                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3427                 exception);
3428               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3429               break;
3430             }
3431             case HorizontalTileVirtualPixelMethod:
3432             {
3433               if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3434                 {
3435                   p=virtual_pixel;
3436                   r=virtual_metacontent;
3437                   break;
3438                 }
3439               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3440               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3441               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3442                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3443                 exception);
3444               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3445               break;
3446             }
3447             case VerticalTileVirtualPixelMethod:
3448             {
3449               if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3450                 {
3451                   p=virtual_pixel;
3452                   r=virtual_metacontent;
3453                   break;
3454                 }
3455               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3456               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3457               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3458                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3459                 exception);
3460               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3461               break;
3462             }
3463           }
3464           if (p == (const Quantum *) NULL)
3465             break;
3466           (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3467             sizeof(*p));
3468           q+=cache_info->number_channels;
3469           if ((s != (void *) NULL) && (r != (const void *) NULL))
3470             {
3471               (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3472               s+=cache_info->metacontent_extent;
3473             }
3474           continue;
3475         }
3476       /*
3477         Transfer a run of pixels.
3478       */
3479       p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3480         length,1UL,*virtual_nexus,exception);
3481       if (p == (const Quantum *) NULL)
3482         break;
3483       r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3484       (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3485       q+=length*cache_info->number_channels;
3486       if ((r != (void *) NULL) && (s != (const void *) NULL))
3487         {
3488           (void) memcpy(s,r,(size_t) length);
3489           s+=length*cache_info->metacontent_extent;
3490         }
3491     }
3492   }
3493   /*
3494     Free resources.
3495   */
3496   if (virtual_metacontent != (void *) NULL)
3497     virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3498   virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3499   return(pixels);
3500 }
3501 \f
3502 /*
3503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3504 %                                                                             %
3505 %                                                                             %
3506 %                                                                             %
3507 +   G e t V i r t u a l P i x e l C a c h e                                   %
3508 %                                                                             %
3509 %                                                                             %
3510 %                                                                             %
3511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3512 %
3513 %  GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3514 %  cache as defined by the geometry parameters.   A pointer to the pixels
3515 %  is returned if the pixels are transferred, otherwise a NULL is returned.
3516 %
3517 %  The format of the GetVirtualPixelCache() method is:
3518 %
3519 %      const Quantum *GetVirtualPixelCache(const Image *image,
3520 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3521 %        const ssize_t y,const size_t columns,const size_t rows,
3522 %        ExceptionInfo *exception)
3523 %
3524 %  A description of each parameter follows:
3525 %
3526 %    o image: the image.
3527 %
3528 %    o virtual_pixel_method: the virtual pixel method.
3529 %
3530 %    o x,y,columns,rows:  These values define the perimeter of a region of
3531 %      pixels.
3532 %
3533 %    o exception: return any errors or warnings in this structure.
3534 %
3535 */
3536 static const Quantum *GetVirtualPixelCache(const Image *image,
3537   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3538   const size_t columns,const size_t rows,ExceptionInfo *exception)
3539 {
3540   CacheInfo
3541     *cache_info;
3542
3543   const int
3544     id = GetOpenMPThreadId();
3545
3546   const Quantum
3547     *p;
3548
3549   assert(image != (const Image *) NULL);
3550   assert(image->signature == MagickSignature);
3551   assert(image->cache != (Cache) NULL);
3552   cache_info=(CacheInfo *) image->cache;
3553   assert(cache_info->signature == MagickSignature);
3554   assert(id < (int) cache_info->number_threads);
3555   p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3556     cache_info->nexus_info[id],exception);
3557   return(p);
3558 }
3559 \f
3560 /*
3561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562 %                                                                             %
3563 %                                                                             %
3564 %                                                                             %
3565 %   G e t V i r t u a l P i x e l Q u e u e                                   %
3566 %                                                                             %
3567 %                                                                             %
3568 %                                                                             %
3569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3570 %
3571 %  GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3572 %  with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3573 %
3574 %  The format of the GetVirtualPixelQueue() method is:
3575 %
3576 %      const Quantum *GetVirtualPixelQueue(const Image image)
3577 %
3578 %  A description of each parameter follows:
3579 %
3580 %    o image: the image.
3581 %
3582 */
3583 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3584 {
3585   CacheInfo
3586     *cache_info;
3587
3588   const int
3589     id = GetOpenMPThreadId();
3590
3591   assert(image != (const Image *) NULL);
3592   assert(image->signature == MagickSignature);
3593   assert(image->cache != (Cache) NULL);
3594   cache_info=(CacheInfo *) image->cache;
3595   assert(cache_info->signature == MagickSignature);
3596   if (cache_info->methods.get_virtual_pixels_handler !=
3597        (GetVirtualPixelsHandler) NULL)
3598     return(cache_info->methods.get_virtual_pixels_handler(image));
3599   assert(id < (int) cache_info->number_threads);
3600   return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3601 }
3602 \f
3603 /*
3604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605 %                                                                             %
3606 %                                                                             %
3607 %                                                                             %
3608 %   G e t V i r t u a l P i x e l s                                           %
3609 %                                                                             %
3610 %                                                                             %
3611 %                                                                             %
3612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3613 %
3614 %  GetVirtualPixels() returns an immutable pixel region. If the
3615 %  region is successfully accessed, a pointer to it is returned, otherwise
3616 %  NULL is returned.  The returned pointer may point to a temporary working
3617 %  copy of the pixels or it may point to the original pixels in memory.
3618 %  Performance is maximized if the selected region is part of one row, or one
3619 %  or more full rows, since there is opportunity to access the pixels in-place
3620 %  (without a copy) if the image is in memory, or in a memory-mapped file.  The
3621 %  returned pointer must *never* be deallocated by the user.
3622 %
3623 %  Pixels accessed via the returned pointer represent a simple array of type
3624 %  Quantum.  If the image type is CMYK or the storage class is PseudoClass,
3625 %  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3626 %  access the meta-content (of type void) corresponding to the the
3627 %  region.
3628 %
3629 %  If you plan to modify the pixels, use GetAuthenticPixels() instead.
3630 %
3631 %  Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3632 %  safe.  In a threaded environment, use GetCacheViewVirtualPixels() or
3633 %  GetCacheViewAuthenticPixels() instead.
3634 %
3635 %  The format of the GetVirtualPixels() method is:
3636 %
3637 %      const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3638 %        const ssize_t y,const size_t columns,const size_t rows,
3639 %        ExceptionInfo *exception)
3640 %
3641 %  A description of each parameter follows:
3642 %
3643 %    o image: the image.
3644 %
3645 %    o x,y,columns,rows:  These values define the perimeter of a region of
3646 %      pixels.
3647 %
3648 %    o exception: return any errors or warnings in this structure.
3649 %
3650 */
3651 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3652   const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3653   ExceptionInfo *exception)
3654 {
3655   CacheInfo
3656     *cache_info;
3657
3658   const int
3659     id = GetOpenMPThreadId();
3660
3661   const Quantum
3662     *p;
3663
3664   assert(image != (const Image *) NULL);
3665   assert(image->signature == MagickSignature);
3666   assert(image->cache != (Cache) NULL);
3667   cache_info=(CacheInfo *) image->cache;
3668   assert(cache_info->signature == MagickSignature);
3669   if (cache_info->methods.get_virtual_pixel_handler !=
3670        (GetVirtualPixelHandler) NULL)
3671     return(cache_info->methods.get_virtual_pixel_handler(image,
3672       GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3673   assert(id < (int) cache_info->number_threads);
3674   p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3675     columns,rows,cache_info->nexus_info[id],exception);
3676   return(p);
3677 }
3678 \f
3679 /*
3680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3681 %                                                                             %
3682 %                                                                             %
3683 %                                                                             %
3684 +   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                         %
3685 %                                                                             %
3686 %                                                                             %
3687 %                                                                             %
3688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3689 %
3690 %  GetVirtualPixelsCache() returns the pixels associated corresponding with the
3691 %  last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3692 %
3693 %  The format of the GetVirtualPixelsCache() method is:
3694 %
3695 %      Quantum *GetVirtualPixelsCache(const Image *image)
3696 %
3697 %  A description of each parameter follows:
3698 %
3699 %    o image: the image.
3700 %
3701 */
3702 static const Quantum *GetVirtualPixelsCache(const Image *image)
3703 {
3704   CacheInfo
3705     *cache_info;
3706
3707   const int
3708     id = GetOpenMPThreadId();
3709
3710   assert(image != (const Image *) NULL);
3711   assert(image->signature == MagickSignature);
3712   assert(image->cache != (Cache) NULL);
3713   cache_info=(CacheInfo *) image->cache;
3714   assert(cache_info->signature == MagickSignature);
3715   assert(id < (int) cache_info->number_threads);
3716   return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3717 }
3718 \f
3719 /*
3720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3721 %                                                                             %
3722 %                                                                             %
3723 %                                                                             %
3724 +   G e t V i r t u a l P i x e l s N e x u s                                 %
3725 %                                                                             %
3726 %                                                                             %
3727 %                                                                             %
3728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3729 %
3730 %  GetVirtualPixelsNexus() returns the pixels associated with the specified
3731 %  cache nexus.
3732 %
3733 %  The format of the GetVirtualPixelsNexus() method is:
3734 %
3735 %      const Quantum *GetVirtualPixelsNexus(const Cache cache,
3736 %        NexusInfo *nexus_info)
3737 %
3738 %  A description of each parameter follows:
3739 %
3740 %    o cache: the pixel cache.
3741 %
3742 %    o nexus_info: the cache nexus to return the colormap pixels.
3743 %
3744 */
3745 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3746   NexusInfo *nexus_info)
3747 {
3748   CacheInfo
3749     *cache_info;
3750
3751   assert(cache != (Cache) NULL);
3752   cache_info=(CacheInfo *) cache;
3753   assert(cache_info->signature == MagickSignature);
3754   if (cache_info->storage_class == UndefinedClass)
3755     return((Quantum *) NULL);
3756   return((const Quantum *) nexus_info->pixels);
3757 }
3758 \f
3759 /*
3760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3761 %                                                                             %
3762 %                                                                             %
3763 %                                                                             %
3764 +   M a s k P i x e l C a c h e N e x u s                                     %
3765 %                                                                             %
3766 %                                                                             %
3767 %                                                                             %
3768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3769 %
3770 %  MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3771 %  The method returns MagickTrue if the pixel region is masked, otherwise
3772 %  MagickFalse.
3773 %
3774 %  The format of the MaskPixelCacheNexus() method is:
3775 %
3776 %      MagickBooleanType MaskPixelCacheNexus(Image *image,
3777 %        NexusInfo *nexus_info,ExceptionInfo *exception)
3778 %
3779 %  A description of each parameter follows:
3780 %
3781 %    o image: the image.
3782 %
3783 %    o nexus_info: the cache nexus to clip.
3784 %
3785 %    o exception: return any errors or warnings in this structure.
3786 %
3787 */
3788
3789 static inline void MagickPixelCompositeMask(const PixelInfo *p,
3790   const MagickRealType alpha,const PixelInfo *q,
3791   const MagickRealType beta,PixelInfo *composite)
3792 {
3793   MagickRealType
3794     gamma;
3795
3796   if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
3797     {
3798       *composite=(*q);
3799       return;
3800     }
3801   gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3802   gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3803   composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3804   composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3805   composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3806   if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3807     composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
3808 }
3809
3810 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3811   ExceptionInfo *exception)
3812 {
3813   CacheInfo
3814     *cache_info;
3815
3816   PixelInfo
3817     alpha,
3818     beta;
3819
3820   MagickSizeType
3821     number_pixels;
3822
3823   NexusInfo
3824     **clip_nexus,
3825     **image_nexus;
3826
3827   register const Quantum
3828     *restrict p,
3829     *restrict r;
3830
3831   register Quantum
3832     *restrict q;
3833
3834   register ssize_t
3835     i;
3836
3837   /*
3838     Apply clip mask.
3839   */
3840   if (image->debug != MagickFalse)
3841     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3842   if (image->mask == (Image *) NULL)
3843     return(MagickFalse);
3844   cache_info=(CacheInfo *) image->cache;
3845   if (cache_info == (Cache) NULL)
3846     return(MagickFalse);
3847   image_nexus=AcquirePixelCacheNexus(1);
3848   clip_nexus=AcquirePixelCacheNexus(1);
3849   if ((image_nexus == (NexusInfo **) NULL) ||
3850       (clip_nexus == (NexusInfo **) NULL))
3851     ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3852   p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3853     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3854     nexus_info->region.height,image_nexus[0],exception);
3855   q=nexus_info->pixels;
3856   r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3857     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3858     nexus_info->region.height,clip_nexus[0],exception);
3859   GetPixelInfo(image,&alpha);
3860   GetPixelInfo(image,&beta);
3861   number_pixels=(MagickSizeType) nexus_info->region.width*
3862     nexus_info->region.height;
3863   for (i=0; i < (ssize_t) number_pixels; i++)
3864   {
3865     if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
3866       break;
3867     GetPixelInfoPixel(image,p,&alpha);
3868     GetPixelInfoPixel(image,q,&beta);
3869     MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3870       &alpha,alpha.alpha,&beta);
3871     SetPixelRed(image,ClampToQuantum(beta.red),q);
3872     SetPixelGreen(image,ClampToQuantum(beta.green),q);
3873     SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3874     if (cache_info->colorspace == CMYKColorspace)
3875       SetPixelBlack(image,ClampToQuantum(beta.black),q);
3876     SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
3877     p++;
3878     q++;
3879     r++;
3880   }
3881   clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3882   image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3883   if (i < (ssize_t) number_pixels)
3884     return(MagickFalse);
3885   return(MagickTrue);
3886 }
3887 \f
3888 /*
3889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3890 %                                                                             %
3891 %                                                                             %
3892 %                                                                             %
3893 +   O p e n P i x e l C a c h e                                               %
3894 %                                                                             %
3895 %                                                                             %
3896 %                                                                             %
3897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3898 %
3899 %  OpenPixelCache() allocates the pixel cache.  This includes defining the cache
3900 %  dimensions, allocating space for the image pixels and optionally the
3901 %  metacontent, and memory mapping the cache if it is disk based.  The cache
3902 %  nexus array is initialized as well.
3903 %
3904 %  The format of the OpenPixelCache() method is:
3905 %
3906 %      MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3907 %        ExceptionInfo *exception)
3908 %
3909 %  A description of each parameter follows:
3910 %
3911 %    o image: the image.
3912 %
3913 %    o mode: ReadMode, WriteMode, or IOMode.
3914 %
3915 %    o exception: return any errors or warnings in this structure.
3916 %
3917 */
3918
3919 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3920 {
3921   cache_info->mapped=MagickFalse;
3922   cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3923     cache_info->length);
3924   if (cache_info->pixels == (Quantum *) NULL)
3925     {
3926       cache_info->mapped=MagickTrue;
3927       cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3928         cache_info->length);
3929     }
3930 }
3931
3932 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3933 {
3934   CacheInfo
3935     *cache_info;
3936
3937   MagickOffsetType
3938     count,
3939     extent,
3940     offset;
3941
3942   cache_info=(CacheInfo *) image->cache;
3943   if (image->debug != MagickFalse)
3944     {
3945       char
3946         format[MaxTextExtent],
3947         message[MaxTextExtent];
3948
3949       (void) FormatMagickSize(length,MagickFalse,format);
3950       (void) FormatLocaleString(message,MaxTextExtent,
3951         "extend %s (%s[%d], disk, %s)",cache_info->filename,
3952         cache_info->cache_filename,cache_info->file,format);
3953       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3954     }
3955   if (length != (MagickSizeType) ((MagickOffsetType) length))
3956     return(MagickFalse);
3957   extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3958   if (extent < 0)
3959     return(MagickFalse);
3960   if ((MagickSizeType) extent >= length)
3961     return(MagickTrue);
3962   offset=(MagickOffsetType) length-1;
3963   count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3964   return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3965 }
3966
3967 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3968   ExceptionInfo *exception)
3969 {
3970   CacheInfo
3971     *cache_info,
3972     source_info;
3973
3974   char
3975     format[MaxTextExtent],
3976     message[MaxTextExtent];
3977
3978   MagickBooleanType
3979     status;
3980
3981   MagickSizeType
3982     length,
3983     number_pixels;
3984
3985   size_t
3986     columns,
3987     packet_size;
3988
3989   assert(image != (const Image *) NULL);
3990   assert(image->signature == MagickSignature);
3991   assert(image->cache != (Cache) NULL);
3992   if (image->debug != MagickFalse)
3993     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3994   if ((image->columns == 0) || (image->rows == 0))
3995     ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3996   cache_info=(CacheInfo *) image->cache;
3997   assert(cache_info->signature == MagickSignature);
3998   source_info=(*cache_info);
3999   source_info.file=(-1);
4000   (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4001     image->filename,(double) GetImageIndexInList(image));
4002   cache_info->storage_class=image->storage_class;
4003   cache_info->colorspace=image->colorspace;
4004   cache_info->matte=image->matte;
4005   cache_info->rows=image->rows;
4006   cache_info->columns=image->columns;
4007   InitializePixelChannelMap(image);
4008   cache_info->number_channels=GetPixelChannels(image);
4009   cache_info->metacontent_extent=image->metacontent_extent;
4010   cache_info->mode=mode;
4011   if (image->ping != MagickFalse)
4012     {
4013       cache_info->type=PingCache;
4014       cache_info->pixels=(Quantum *) NULL;
4015       cache_info->metacontent=(void *) NULL;
4016       cache_info->length=0;
4017       return(MagickTrue);
4018     }
4019   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4020   packet_size=cache_info->number_channels*sizeof(Quantum);
4021   if (image->metacontent_extent != 0)
4022     packet_size+=cache_info->metacontent_extent;
4023   length=number_pixels*packet_size;
4024   columns=(size_t) (length/cache_info->rows/packet_size);
4025   if (cache_info->columns != columns)
4026     ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4027       image->filename);
4028   cache_info->length=length;
4029   if ((cache_info->type != UndefinedCache) &&
4030       (cache_info->columns <= source_info.columns) &&
4031       (cache_info->rows <= source_info.rows) &&
4032       (cache_info->number_channels <= source_info.number_channels) &&
4033       (cache_info->metacontent_extent <= source_info.metacontent_extent))
4034     {
4035       /*
4036         Inline pixel cache clone optimization.
4037       */
4038       if ((cache_info->columns == source_info.columns) &&
4039           (cache_info->rows == source_info.rows) &&
4040           (cache_info->number_channels == source_info.number_channels) &&
4041           (cache_info->metacontent_extent == source_info.metacontent_extent))
4042         return(MagickTrue);
4043       return(ClonePixelCachePixels(cache_info,&source_info,exception));
4044     }
4045   status=AcquireMagickResource(AreaResource,cache_info->length);
4046   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4047     cache_info->metacontent_extent);
4048   if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4049     {
4050       status=AcquireMagickResource(MemoryResource,cache_info->length);
4051       if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4052           (cache_info->type == MemoryCache))
4053         {
4054           AllocatePixelCachePixels(cache_info);
4055           if (cache_info->pixels == (Quantum *) NULL)
4056             cache_info->pixels=source_info.pixels;
4057           else
4058             {
4059               /*
4060                 Create memory pixel cache.
4061               */
4062               status=MagickTrue;
4063               if (image->debug != MagickFalse)
4064                 {
4065                   (void) FormatMagickSize(cache_info->length,MagickTrue,
4066                     format);
4067                   (void) FormatLocaleString(message,MaxTextExtent,
4068                     "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4069                     cache_info->filename,cache_info->mapped != MagickFalse ?
4070                     "anonymous" : "heap",(double) cache_info->columns,(double)
4071                     cache_info->rows,(double) cache_info->number_channels,
4072                     format);
4073                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4074                     message);
4075                 }
4076               cache_info->type=MemoryCache;
4077               cache_info->metacontent=(void *) NULL;
4078               if (cache_info->metacontent_extent != 0)
4079                 cache_info->metacontent=(void *) (cache_info->pixels+
4080                   number_pixels*cache_info->number_channels);
4081               if (source_info.storage_class != UndefinedClass)
4082                 {
4083                   status=ClonePixelCachePixels(cache_info,&source_info,
4084                     exception);
4085                   RelinquishPixelCachePixels(&source_info);
4086                 }
4087               return(status);
4088             }
4089         }
4090       RelinquishMagickResource(MemoryResource,cache_info->length);
4091     }
4092   /*
4093     Create pixel cache on disk.
4094   */
4095   status=AcquireMagickResource(DiskResource,cache_info->length);
4096   if (status == MagickFalse)
4097     {
4098       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4099         "CacheResourcesExhausted","`%s'",image->filename);
4100       return(MagickFalse);
4101     }
4102   if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4103     {
4104       RelinquishMagickResource(DiskResource,cache_info->length);
4105       ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4106         image->filename);
4107       return(MagickFalse);
4108     }
4109   status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4110     cache_info->length);
4111   if (status == MagickFalse)
4112     {
4113       ThrowFileException(exception,CacheError,"UnableToExtendCache",
4114         image->filename);
4115       return(MagickFalse);
4116     }
4117   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4118     cache_info->metacontent_extent);
4119   if (length != (MagickSizeType) ((size_t) length))
4120     cache_info->type=DiskCache;
4121   else
4122     {
4123       status=AcquireMagickResource(MapResource,cache_info->length);
4124       if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4125           (cache_info->type != MemoryCache))
4126         cache_info->type=DiskCache;
4127       else
4128         {
4129           cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4130             cache_info->offset,(size_t) cache_info->length);
4131           if (cache_info->pixels == (Quantum *) NULL)
4132             {
4133               cache_info->type=DiskCache;
4134               cache_info->pixels=source_info.pixels;
4135             }
4136           else
4137             {
4138               /*
4139                 Create file-backed memory-mapped pixel cache.
4140               */
4141               status=MagickTrue;
4142               (void) ClosePixelCacheOnDisk(cache_info);
4143               cache_info->type=MapCache;
4144               cache_info->mapped=MagickTrue;
4145               cache_info->metacontent=(void *) NULL;
4146               if (cache_info->metacontent_extent != 0)
4147                 cache_info->metacontent=(void *) (cache_info->pixels+
4148                   number_pixels*cache_info->number_channels);
4149               if (source_info.storage_class != UndefinedClass)
4150                 {
4151                   status=ClonePixelCachePixels(cache_info,&source_info,
4152                     exception);
4153                   RelinquishPixelCachePixels(&source_info);
4154                 }
4155               if (image->debug != MagickFalse)
4156                 {
4157                   (void) FormatMagickSize(cache_info->length,MagickTrue,
4158                     format);
4159                   (void) FormatLocaleString(message,MaxTextExtent,
4160                     "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4161                     cache_info->filename,cache_info->cache_filename,
4162                     cache_info->file,(double) cache_info->columns,(double)
4163                     cache_info->rows,(double) cache_info->number_channels,
4164                     format);
4165                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4166                     message);
4167                 }
4168               return(status);
4169             }
4170         }
4171       RelinquishMagickResource(MapResource,cache_info->length);
4172     }
4173   status=MagickTrue;
4174   if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4175     {
4176       status=ClonePixelCachePixels(cache_info,&source_info,exception);
4177       RelinquishPixelCachePixels(&source_info);
4178     }
4179   if (image->debug != MagickFalse)
4180     {
4181       (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4182       (void) FormatLocaleString(message,MaxTextExtent,
4183         "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4184         cache_info->cache_filename,cache_info->file,(double)
4185         cache_info->columns,(double) cache_info->rows,(double)
4186         cache_info->number_channels,format);
4187       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4188     }
4189   return(status);
4190 }
4191 \f
4192 /*
4193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4194 %                                                                             %
4195 %                                                                             %
4196 %                                                                             %
4197 +   P e r s i s t P i x e l C a c h e                                         %
4198 %                                                                             %
4199 %                                                                             %
4200 %                                                                             %
4201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4202 %
4203 %  PersistPixelCache() attaches to or initializes a persistent pixel cache.  A
4204 %  persistent pixel cache is one that resides on disk and is not destroyed
4205 %  when the program exits.
4206 %
4207 %  The format of the PersistPixelCache() method is:
4208 %
4209 %      MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4210 %        const MagickBooleanType attach,MagickOffsetType *offset,
4211 %        ExceptionInfo *exception)
4212 %
4213 %  A description of each parameter follows:
4214 %
4215 %    o image: the image.
4216 %
4217 %    o filename: the persistent pixel cache filename.
4218 %
4219 %    o attach: A value other than zero initializes the persistent pixel cache.
4220 %
4221 %    o initialize: A value other than zero initializes the persistent pixel
4222 %      cache.
4223 %
4224 %    o offset: the offset in the persistent cache to store pixels.
4225 %
4226 %    o exception: return any errors or warnings in this structure.
4227 %
4228 */
4229 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4230   const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4231   ExceptionInfo *exception)
4232 {
4233   CacheInfo
4234     *cache_info,
4235     *clone_info;
4236
4237   Image
4238     clone_image;
4239
4240   MagickBooleanType
4241     status;
4242
4243   ssize_t
4244     page_size;
4245
4246   assert(image != (Image *) NULL);
4247   assert(image->signature == MagickSignature);
4248   if (image->debug != MagickFalse)
4249     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4250   assert(image->cache != (void *) NULL);
4251   assert(filename != (const char *) NULL);
4252   assert(offset != (MagickOffsetType *) NULL);
4253   page_size=GetMagickPageSize();
4254   cache_info=(CacheInfo *) image->cache;
4255   assert(cache_info->signature == MagickSignature);
4256   if (attach != MagickFalse)
4257     {
4258       /*
4259         Attach existing persistent pixel cache.
4260       */
4261       if (image->debug != MagickFalse)
4262         (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4263           "attach persistent cache");
4264       (void) CopyMagickString(cache_info->cache_filename,filename,
4265         MaxTextExtent);
4266       cache_info->type=DiskCache;
4267       cache_info->offset=(*offset);
4268       if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4269         return(MagickFalse);
4270       *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4271       return(MagickTrue);
4272     }
4273   if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4274       (cache_info->reference_count == 1))
4275     {
4276       LockSemaphoreInfo(cache_info->semaphore);
4277       if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4278           (cache_info->reference_count == 1))
4279         {
4280           int
4281             status;
4282
4283           /*
4284             Usurp existing persistent pixel cache.
4285           */
4286           status=rename_utf8(cache_info->cache_filename,filename);
4287           if (status == 0)
4288             {
4289               (void) CopyMagickString(cache_info->cache_filename,filename,
4290                 MaxTextExtent);
4291               *offset+=cache_info->length+page_size-(cache_info->length %
4292                 page_size);
4293               UnlockSemaphoreInfo(cache_info->semaphore);
4294               cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4295               if (image->debug != MagickFalse)
4296                 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4297                   "Usurp resident persistent cache");
4298               return(MagickTrue);
4299             }
4300         }
4301       UnlockSemaphoreInfo(cache_info->semaphore);
4302     }
4303   /*
4304     Clone persistent pixel cache.
4305   */
4306   clone_image=(*image);
4307   clone_info=(CacheInfo *) clone_image.cache;
4308   image->cache=ClonePixelCache(cache_info);
4309   cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4310   (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4311   cache_info->type=DiskCache;
4312   cache_info->offset=(*offset);
4313   cache_info=(CacheInfo *) image->cache;
4314   status=OpenPixelCache(image,IOMode,exception);
4315   if (status != MagickFalse)
4316     status=ClonePixelCachePixels(cache_info,clone_info,exception);
4317   *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4318   clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4319   return(status);
4320 }
4321 \f
4322 /*
4323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4324 %                                                                             %
4325 %                                                                             %
4326 %                                                                             %
4327 +   Q u e u e A u t h e n t i c N e x u s                                     %
4328 %                                                                             %
4329 %                                                                             %
4330 %                                                                             %
4331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4332 %
4333 %  QueueAuthenticNexus() allocates an region to store image pixels as defined
4334 %  by the region rectangle and returns a pointer to the region.  This region is
4335 %  subsequently transferred from the pixel cache with
4336 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4337 %  pixels are transferred, otherwise a NULL is returned.
4338 %
4339 %  The format of the QueueAuthenticNexus() method is:
4340 %
4341 %      Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4342 %        const ssize_t y,const size_t columns,const size_t rows,
4343 %        const MagickBooleanType clone,NexusInfo *nexus_info,
4344 %        ExceptionInfo *exception)
4345 %
4346 %  A description of each parameter follows:
4347 %
4348 %    o image: the image.
4349 %
4350 %    o x,y,columns,rows:  These values define the perimeter of a region of
4351 %      pixels.
4352 %
4353 %    o nexus_info: the cache nexus to set.
4354 %
4355 %    o clone: clone the pixel cache.
4356 %
4357 %    o exception: return any errors or warnings in this structure.
4358 %
4359 */
4360 MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4361   const ssize_t y,const size_t columns,const size_t rows,
4362   const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4363 {
4364   CacheInfo
4365     *cache_info;
4366
4367   MagickOffsetType
4368     offset;
4369
4370   MagickSizeType
4371     number_pixels;
4372
4373   RectangleInfo
4374     region;
4375
4376   /*
4377     Validate pixel cache geometry.
4378   */
4379   assert(image != (const Image *) NULL);
4380   assert(image->signature == MagickSignature);
4381   assert(image->cache != (Cache) NULL);
4382   cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4383   if (cache_info == (Cache) NULL)
4384     return((Quantum *) NULL);
4385   assert(cache_info->signature == MagickSignature);
4386   if ((cache_info->columns == 0) && (cache_info->rows == 0))
4387     {
4388       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4389         "NoPixelsDefinedInCache","`%s'",image->filename);
4390       return((Quantum *) NULL);
4391     }
4392   if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4393       (y >= (ssize_t) cache_info->rows))
4394     {
4395       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4396         "PixelsAreNotAuthentic","`%s'",image->filename);
4397       return((Quantum *) NULL);
4398     }
4399   offset=(MagickOffsetType) y*cache_info->columns+x;
4400   if (offset < 0)
4401     return((Quantum *) NULL);
4402   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4403   offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4404   if ((MagickSizeType) offset >= number_pixels)
4405     return((Quantum *) NULL);
4406   /*
4407     Return pixel cache.
4408   */
4409   region.x=x;
4410   region.y=y;
4411   region.width=columns;
4412   region.height=rows;
4413   return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4414 }
4415 \f
4416 /*
4417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4418 %                                                                             %
4419 %                                                                             %
4420 %                                                                             %
4421 +   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                         %
4422 %                                                                             %
4423 %                                                                             %
4424 %                                                                             %
4425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4426 %
4427 %  QueueAuthenticPixelsCache() allocates an region to store image pixels as
4428 %  defined by the region rectangle and returns a pointer to the region.  This
4429 %  region is subsequently transferred from the pixel cache with
4430 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4431 %  pixels are transferred, otherwise a NULL is returned.
4432 %
4433 %  The format of the QueueAuthenticPixelsCache() method is:
4434 %
4435 %      Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4436 %        const ssize_t y,const size_t columns,const size_t rows,
4437 %        ExceptionInfo *exception)
4438 %
4439 %  A description of each parameter follows:
4440 %
4441 %    o image: the image.
4442 %
4443 %    o x,y,columns,rows:  These values define the perimeter of a region of
4444 %      pixels.
4445 %
4446 %    o exception: return any errors or warnings in this structure.
4447 %
4448 */
4449 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4450   const ssize_t y,const size_t columns,const size_t rows,
4451   ExceptionInfo *exception)
4452 {
4453   CacheInfo
4454     *cache_info;
4455
4456   const int
4457     id = GetOpenMPThreadId();
4458
4459   Quantum
4460     *q;
4461
4462   assert(image != (const Image *) NULL);
4463   assert(image->signature == MagickSignature);
4464   assert(image->cache != (Cache) NULL);
4465   cache_info=(CacheInfo *) image->cache;
4466   assert(cache_info->signature == MagickSignature);
4467   assert(id < (int) cache_info->number_threads);
4468   q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4469     cache_info->nexus_info[id],exception);
4470   return(q);
4471 }
4472 \f
4473 /*
4474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4475 %                                                                             %
4476 %                                                                             %
4477 %                                                                             %
4478 %   Q u e u e A u t h e n t i c P i x e l s                                   %
4479 %                                                                             %
4480 %                                                                             %
4481 %                                                                             %
4482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4483 %
4484 %  QueueAuthenticPixels() queues a mutable pixel region.  If the region is
4485 %  successfully initialized a pointer to a Quantum array representing the
4486 %  region is returned, otherwise NULL is returned.  The returned pointer may
4487 %  point to a temporary working buffer for the pixels or it may point to the
4488 %  final location of the pixels in memory.
4489 %
4490 %  Write-only access means that any existing pixel values corresponding to
4491 %  the region are ignored.  This is useful if the initial image is being
4492 %  created from scratch, or if the existing pixel values are to be
4493 %  completely replaced without need to refer to their pre-existing values.
4494 %  The application is free to read and write the pixel buffer returned by
4495 %  QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4496 %  initialize the pixel array values. Initializing pixel array values is the
4497 %  application's responsibility.
4498 %
4499 %  Performance is maximized if the selected region is part of one row, or
4500 %  one or more full rows, since then there is opportunity to access the
4501 %  pixels in-place (without a copy) if the image is in memory, or in a
4502 %  memory-mapped file. The returned pointer must *never* be deallocated
4503 %  by the user.
4504 %
4505 %  Pixels accessed via the returned pointer represent a simple array of type
4506 %  Quantum. If the image type is CMYK or the storage class is PseudoClass,
4507 %  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4508 %  obtain the meta-content (of type void) corresponding to the region.
4509 %  Once the Quantum (and/or Quantum) array has been updated, the
4510 %  changes must be saved back to the underlying image using
4511 %  SyncAuthenticPixels() or they may be lost.
4512 %
4513 %  The format of the QueueAuthenticPixels() method is:
4514 %
4515 %      Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4516 %        const ssize_t y,const size_t columns,const size_t rows,
4517 %        ExceptionInfo *exception)
4518 %
4519 %  A description of each parameter follows:
4520 %
4521 %    o image: the image.
4522 %
4523 %    o x,y,columns,rows:  These values define the perimeter of a region of
4524 %      pixels.
4525 %
4526 %    o exception: return any errors or warnings in this structure.
4527 %
4528 */
4529 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4530   const ssize_t y,const size_t columns,const size_t rows,
4531   ExceptionInfo *exception)
4532 {
4533   CacheInfo
4534     *cache_info;
4535
4536   const int
4537     id = GetOpenMPThreadId();
4538
4539   Quantum
4540     *q;
4541
4542   assert(image != (Image *) NULL);
4543   assert(image->signature == MagickSignature);
4544   assert(image->cache != (Cache) NULL);
4545   cache_info=(CacheInfo *) image->cache;
4546   assert(cache_info->signature == MagickSignature);
4547   if (cache_info->methods.queue_authentic_pixels_handler !=
4548        (QueueAuthenticPixelsHandler) NULL)
4549     {
4550       q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4551         columns,rows,exception);
4552       return(q);
4553     }
4554   assert(id < (int) cache_info->number_threads);
4555   q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4556     cache_info->nexus_info[id],exception);
4557   return(q);
4558 }
4559 \f
4560 /*
4561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4562 %                                                                             %
4563 %                                                                             %
4564 %                                                                             %
4565 +   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                         %
4566 %                                                                             %
4567 %                                                                             %
4568 %                                                                             %
4569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4570 %
4571 %  ReadPixelCacheMetacontent() reads metacontent from the specified region of
4572 %  the pixel cache.
4573 %
4574 %  The format of the ReadPixelCacheMetacontent() method is:
4575 %
4576 %      MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4577 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4578 %
4579 %  A description of each parameter follows:
4580 %
4581 %    o cache_info: the pixel cache.
4582 %
4583 %    o nexus_info: the cache nexus to read the metacontent.
4584 %
4585 %    o exception: return any errors or warnings in this structure.
4586 %
4587 */
4588 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4589   NexusInfo *nexus_info,ExceptionInfo *exception)
4590 {
4591   MagickOffsetType
4592     count,
4593     offset;
4594
4595   MagickSizeType
4596     extent,
4597     length;
4598
4599   register ssize_t
4600     y;
4601
4602   register unsigned char
4603     *restrict q;
4604
4605   size_t
4606     rows;
4607
4608   if (cache_info->metacontent_extent == 0)
4609     return(MagickFalse);
4610   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4611     return(MagickTrue);
4612   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4613     nexus_info->region.x;
4614   length=(MagickSizeType) nexus_info->region.width*
4615     cache_info->metacontent_extent;
4616   rows=nexus_info->region.height;
4617   extent=length*rows;
4618   q=(unsigned char *) nexus_info->metacontent;
4619   switch (cache_info->type)
4620   {
4621     case MemoryCache:
4622     case MapCache:
4623     {
4624       register unsigned char
4625         *restrict p;
4626
4627       /*
4628         Read meta-content from memory.
4629       */
4630       if ((cache_info->columns == nexus_info->region.width) &&
4631           (extent == (MagickSizeType) ((size_t) extent)))
4632         {
4633           length=extent;
4634           rows=1UL;
4635         }
4636       p=(unsigned char *) cache_info->metacontent+offset*
4637         cache_info->metacontent_extent;
4638       for (y=0; y < (ssize_t) rows; y++)
4639       {
4640         (void) memcpy(q,p,(size_t) length);
4641         p+=cache_info->metacontent_extent*cache_info->columns;
4642         q+=cache_info->metacontent_extent*nexus_info->region.width;
4643       }
4644       break;
4645     }
4646     case DiskCache:
4647     {
4648       /*
4649         Read meta content from disk.
4650       */
4651       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4652         {
4653           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4654             cache_info->cache_filename);
4655           return(MagickFalse);
4656         }
4657       if ((cache_info->columns == nexus_info->region.width) &&
4658           (extent <= MagickMaxBufferExtent))
4659         {
4660           length=extent;
4661           rows=1UL;
4662         }
4663       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4664       for (y=0; y < (ssize_t) rows; y++)
4665       {
4666         count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4667           cache_info->number_channels*sizeof(Quantum)+offset*
4668           cache_info->metacontent_extent,length,(unsigned char *) q);
4669         if ((MagickSizeType) count != length)
4670           break;
4671         offset+=cache_info->columns;
4672         q+=cache_info->metacontent_extent*nexus_info->region.width;
4673       }
4674       if (y < (ssize_t) rows)
4675         {
4676           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4677             cache_info->cache_filename);
4678           return(MagickFalse);
4679         }
4680       break;
4681     }
4682     default:
4683       break;
4684   }
4685   if ((cache_info->debug != MagickFalse) &&
4686       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4687     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4688       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4689       nexus_info->region.width,(double) nexus_info->region.height,(double)
4690       nexus_info->region.x,(double) nexus_info->region.y);
4691   return(MagickTrue);
4692 }
4693 \f
4694 /*
4695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4696 %                                                                             %
4697 %                                                                             %
4698 %                                                                             %
4699 +   R e a d P i x e l C a c h e P i x e l s                                   %
4700 %                                                                             %
4701 %                                                                             %
4702 %                                                                             %
4703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4704 %
4705 %  ReadPixelCachePixels() reads pixels from the specified region of the pixel
4706 %  cache.
4707 %
4708 %  The format of the ReadPixelCachePixels() method is:
4709 %
4710 %      MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4711 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4712 %
4713 %  A description of each parameter follows:
4714 %
4715 %    o cache_info: the pixel cache.
4716 %
4717 %    o nexus_info: the cache nexus to read the pixels.
4718 %
4719 %    o exception: return any errors or warnings in this structure.
4720 %
4721 */
4722 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4723   NexusInfo *nexus_info,ExceptionInfo *exception)
4724 {
4725   MagickOffsetType
4726     count,
4727     offset;
4728
4729   MagickSizeType
4730     extent,
4731     length;
4732
4733   register Quantum
4734     *restrict q;
4735
4736   register ssize_t
4737     y;
4738
4739   size_t
4740     rows;
4741
4742   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4743     return(MagickTrue);
4744   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4745     nexus_info->region.x;
4746   length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4747     sizeof(Quantum);
4748   rows=nexus_info->region.height;
4749   extent=length*rows;
4750   q=nexus_info->pixels;
4751   switch (cache_info->type)
4752   {
4753     case MemoryCache:
4754     case MapCache:
4755     {
4756       register Quantum
4757         *restrict p;
4758
4759       /*
4760         Read pixels from memory.
4761       */
4762       if ((cache_info->columns == nexus_info->region.width) &&
4763           (extent == (MagickSizeType) ((size_t) extent)))
4764         {
4765           length=extent;
4766           rows=1UL;
4767         }
4768       p=cache_info->pixels+offset*cache_info->number_channels;
4769       for (y=0; y < (ssize_t) rows; y++)
4770       {
4771         (void) memcpy(q,p,(size_t) length);
4772         p+=cache_info->number_channels*cache_info->columns;
4773         q+=cache_info->number_channels*nexus_info->region.width;
4774       }
4775       break;
4776     }
4777     case DiskCache:
4778     {
4779       /*
4780         Read pixels from disk.
4781       */
4782       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4783         {
4784           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4785             cache_info->cache_filename);
4786           return(MagickFalse);
4787         }
4788       if ((cache_info->columns == nexus_info->region.width) &&
4789           (extent <= MagickMaxBufferExtent))
4790         {
4791           length=extent;
4792           rows=1UL;
4793         }
4794       for (y=0; y < (ssize_t) rows; y++)
4795       {
4796         count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4797           cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4798         if ((MagickSizeType) count != length)
4799           break;
4800         offset+=cache_info->columns;
4801         q+=cache_info->number_channels*nexus_info->region.width;
4802       }
4803       if (y < (ssize_t) rows)
4804         {
4805           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4806             cache_info->cache_filename);
4807           return(MagickFalse);
4808         }
4809       break;
4810     }
4811     default:
4812       break;
4813   }
4814   if ((cache_info->debug != MagickFalse) &&
4815       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4816     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4817       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4818       nexus_info->region.width,(double) nexus_info->region.height,(double)
4819       nexus_info->region.x,(double) nexus_info->region.y);
4820   return(MagickTrue);
4821 }
4822 \f
4823 /*
4824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4825 %                                                                             %
4826 %                                                                             %
4827 %                                                                             %
4828 +   R e f e r e n c e P i x e l C a c h e                                     %
4829 %                                                                             %
4830 %                                                                             %
4831 %                                                                             %
4832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4833 %
4834 %  ReferencePixelCache() increments the reference count associated with the
4835 %  pixel cache returning a pointer to the cache.
4836 %
4837 %  The format of the ReferencePixelCache method is:
4838 %
4839 %      Cache ReferencePixelCache(Cache cache_info)
4840 %
4841 %  A description of each parameter follows:
4842 %
4843 %    o cache_info: the pixel cache.
4844 %
4845 */
4846 MagickPrivate Cache ReferencePixelCache(Cache cache)
4847 {
4848   CacheInfo
4849     *cache_info;
4850
4851   assert(cache != (Cache *) NULL);
4852   cache_info=(CacheInfo *) cache;
4853   assert(cache_info->signature == MagickSignature);
4854   LockSemaphoreInfo(cache_info->semaphore);
4855   cache_info->reference_count++;
4856   UnlockSemaphoreInfo(cache_info->semaphore);
4857   return(cache_info);
4858 }
4859 \f
4860 /*
4861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4862 %                                                                             %
4863 %                                                                             %
4864 %                                                                             %
4865 +   S e t P i x e l C a c h e M e t h o d s                                   %
4866 %                                                                             %
4867 %                                                                             %
4868 %                                                                             %
4869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4870 %
4871 %  SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4872 %
4873 %  The format of the SetPixelCacheMethods() method is:
4874 %
4875 %      SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4876 %
4877 %  A description of each parameter follows:
4878 %
4879 %    o cache: the pixel cache.
4880 %
4881 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
4882 %
4883 */
4884 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4885 {
4886   CacheInfo
4887     *cache_info;
4888
4889   GetOneAuthenticPixelFromHandler
4890     get_one_authentic_pixel_from_handler;
4891
4892   GetOneVirtualPixelFromHandler
4893     get_one_virtual_pixel_from_handler;
4894
4895   /*
4896     Set cache pixel methods.
4897   */
4898   assert(cache != (Cache) NULL);
4899   assert(cache_methods != (CacheMethods *) NULL);
4900   cache_info=(CacheInfo *) cache;
4901   assert(cache_info->signature == MagickSignature);
4902   if (cache_info->debug != MagickFalse)
4903     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4904       cache_info->filename);
4905   if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4906     cache_info->methods.get_virtual_pixel_handler=
4907       cache_methods->get_virtual_pixel_handler;
4908   if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4909     cache_info->methods.destroy_pixel_handler=
4910       cache_methods->destroy_pixel_handler;
4911   if (cache_methods->get_virtual_metacontent_from_handler !=
4912       (GetVirtualMetacontentFromHandler) NULL)
4913     cache_info->methods.get_virtual_metacontent_from_handler=
4914       cache_methods->get_virtual_metacontent_from_handler;
4915   if (cache_methods->get_authentic_pixels_handler !=
4916       (GetAuthenticPixelsHandler) NULL)
4917     cache_info->methods.get_authentic_pixels_handler=
4918       cache_methods->get_authentic_pixels_handler;
4919   if (cache_methods->queue_authentic_pixels_handler !=
4920       (QueueAuthenticPixelsHandler) NULL)
4921     cache_info->methods.queue_authentic_pixels_handler=
4922       cache_methods->queue_authentic_pixels_handler;
4923   if (cache_methods->sync_authentic_pixels_handler !=
4924       (SyncAuthenticPixelsHandler) NULL)
4925     cache_info->methods.sync_authentic_pixels_handler=
4926       cache_methods->sync_authentic_pixels_handler;
4927   if (cache_methods->get_authentic_pixels_from_handler !=
4928       (GetAuthenticPixelsFromHandler) NULL)
4929     cache_info->methods.get_authentic_pixels_from_handler=
4930       cache_methods->get_authentic_pixels_from_handler;
4931   if (cache_methods->get_authentic_metacontent_from_handler !=
4932       (GetAuthenticMetacontentFromHandler) NULL)
4933     cache_info->methods.get_authentic_metacontent_from_handler=
4934       cache_methods->get_authentic_metacontent_from_handler;
4935   get_one_virtual_pixel_from_handler=
4936     cache_info->methods.get_one_virtual_pixel_from_handler;
4937   if (get_one_virtual_pixel_from_handler !=
4938       (GetOneVirtualPixelFromHandler) NULL)
4939     cache_info->methods.get_one_virtual_pixel_from_handler=
4940       cache_methods->get_one_virtual_pixel_from_handler;
4941   get_one_authentic_pixel_from_handler=
4942     cache_methods->get_one_authentic_pixel_from_handler;
4943   if (get_one_authentic_pixel_from_handler !=
4944       (GetOneAuthenticPixelFromHandler) NULL)
4945     cache_info->methods.get_one_authentic_pixel_from_handler=
4946       cache_methods->get_one_authentic_pixel_from_handler;
4947 }
4948 \f
4949 /*
4950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4951 %                                                                             %
4952 %                                                                             %
4953 %                                                                             %
4954 +   S e t P i x e l C a c h e N e x u s P i x e l s                           %
4955 %                                                                             %
4956 %                                                                             %
4957 %                                                                             %
4958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4959 %
4960 %  SetPixelCacheNexusPixels() defines the region of the cache for the
4961 %  specified cache nexus.
4962 %
4963 %  The format of the SetPixelCacheNexusPixels() method is:
4964 %
4965 %      Quantum SetPixelCacheNexusPixels(const Image *image,
4966 %        const RectangleInfo *region,NexusInfo *nexus_info,
4967 %        ExceptionInfo *exception)
4968 %
4969 %  A description of each parameter follows:
4970 %
4971 %    o image: the image.
4972 %
4973 %    o region: A pointer to the RectangleInfo structure that defines the
4974 %      region of this particular cache nexus.
4975 %
4976 %    o nexus_info: the cache nexus to set.
4977 %
4978 %    o exception: return any errors or warnings in this structure.
4979 %
4980 */
4981
4982 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4983   NexusInfo *nexus_info,ExceptionInfo *exception)
4984 {
4985   if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4986     return(MagickFalse);
4987   nexus_info->mapped=MagickFalse;
4988   nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
4989     nexus_info->length);
4990   if (nexus_info->cache == (Quantum *) NULL)
4991     {
4992       nexus_info->mapped=MagickTrue;
4993       nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4994         nexus_info->length);
4995     }
4996   if (nexus_info->cache == (Quantum *) NULL)
4997     {
4998       (void) ThrowMagickException(exception,GetMagickModule(),
4999         ResourceLimitError,"MemoryAllocationFailed","`%s'",
5000         cache_info->filename);
5001       return(MagickFalse);
5002     }
5003   return(MagickTrue);
5004 }
5005
5006 static Quantum *SetPixelCacheNexusPixels(const Image *image,
5007   const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5008 {
5009   CacheInfo
5010     *cache_info;
5011
5012   MagickBooleanType
5013     status;
5014
5015   MagickSizeType
5016     length,
5017     number_pixels;
5018
5019   cache_info=(CacheInfo *) image->cache;
5020   assert(cache_info->signature == MagickSignature);
5021   if (cache_info->type == UndefinedCache)
5022     return((Quantum *) NULL);
5023   nexus_info->region=(*region);
5024   if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5025       (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5026     {
5027       ssize_t
5028         x,
5029         y;
5030
5031       x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5032       y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5033       if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5034            (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5035           ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5036            ((nexus_info->region.width == cache_info->columns) ||
5037             ((nexus_info->region.width % cache_info->columns) == 0)))))
5038         {
5039           MagickOffsetType
5040             offset;
5041
5042           /*
5043             Pixels are accessed directly from memory.
5044           */
5045           offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5046             nexus_info->region.x;
5047           nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5048             offset;
5049           nexus_info->metacontent=(void *) NULL;
5050           if (cache_info->metacontent_extent != 0)
5051             nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5052               offset*cache_info->metacontent_extent;
5053           return(nexus_info->pixels);
5054         }
5055     }
5056   /*
5057     Pixels are stored in a cache region until they are synced to the cache.
5058   */
5059   number_pixels=(MagickSizeType) nexus_info->region.width*
5060     nexus_info->region.height;
5061   length=number_pixels*cache_info->number_channels*sizeof(Quantum);
5062   if (cache_info->metacontent_extent != 0)
5063     length+=number_pixels*cache_info->metacontent_extent;
5064   if (nexus_info->cache == (Quantum *) NULL)
5065     {
5066       nexus_info->length=length;
5067       status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5068       if (status == MagickFalse)
5069         {
5070           nexus_info->length=0;
5071           return((Quantum *) NULL);
5072         }
5073     }
5074   else
5075     if (nexus_info->length != length)
5076       {
5077         RelinquishCacheNexusPixels(nexus_info);
5078         nexus_info->length=length;
5079         status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5080         if (status == MagickFalse)
5081           {
5082             nexus_info->length=0;
5083             return((Quantum *) NULL);
5084           }
5085       }
5086   nexus_info->pixels=nexus_info->cache;
5087   nexus_info->metacontent=(void *) NULL;
5088   if (cache_info->metacontent_extent != 0)
5089     nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
5090       cache_info->number_channels);
5091   return(nexus_info->pixels);
5092 }
5093 \f
5094 /*
5095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5096 %                                                                             %
5097 %                                                                             %
5098 %                                                                             %
5099 %   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                       %
5100 %                                                                             %
5101 %                                                                             %
5102 %                                                                             %
5103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5104 %
5105 %  SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5106 %  pixel cache and returns the previous setting.  A virtual pixel is any pixel
5107 %  access that is outside the boundaries of the image cache.
5108 %
5109 %  The format of the SetPixelCacheVirtualMethod() method is:
5110 %
5111 %      VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5112 %        const VirtualPixelMethod virtual_pixel_method)
5113 %
5114 %  A description of each parameter follows:
5115 %
5116 %    o image: the image.
5117 %
5118 %    o virtual_pixel_method: choose the type of virtual pixel.
5119 %
5120 */
5121 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5122   const VirtualPixelMethod virtual_pixel_method)
5123 {
5124   CacheInfo
5125     *cache_info;
5126
5127   VirtualPixelMethod
5128     method;
5129
5130   assert(image != (Image *) NULL);
5131   assert(image->signature == MagickSignature);
5132   if (image->debug != MagickFalse)
5133     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5134   assert(image->cache != (Cache) NULL);
5135   cache_info=(CacheInfo *) image->cache;
5136   assert(cache_info->signature == MagickSignature);
5137   method=cache_info->virtual_pixel_method;
5138   cache_info->virtual_pixel_method=virtual_pixel_method;
5139   return(method);
5140 }
5141 \f
5142 /*
5143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5144 %                                                                             %
5145 %                                                                             %
5146 %                                                                             %
5147 +   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                   %
5148 %                                                                             %
5149 %                                                                             %
5150 %                                                                             %
5151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5152 %
5153 %  SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5154 %  in-memory or disk cache.  The method returns MagickTrue if the pixel region
5155 %  is synced, otherwise MagickFalse.
5156 %
5157 %  The format of the SyncAuthenticPixelCacheNexus() method is:
5158 %
5159 %      MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5160 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5161 %
5162 %  A description of each parameter follows:
5163 %
5164 %    o image: the image.
5165 %
5166 %    o nexus_info: the cache nexus to sync.
5167 %
5168 %    o exception: return any errors or warnings in this structure.
5169 %
5170 */
5171 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5172   NexusInfo *nexus_info,ExceptionInfo *exception)
5173 {
5174   CacheInfo
5175     *cache_info;
5176
5177   MagickBooleanType
5178     status;
5179
5180   /*
5181     Transfer pixels to the cache.
5182   */
5183   assert(image != (Image *) NULL);
5184   assert(image->signature == MagickSignature);
5185   if (image->cache == (Cache) NULL)
5186     ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5187   cache_info=(CacheInfo *) image->cache;
5188   assert(cache_info->signature == MagickSignature);
5189   if (cache_info->type == UndefinedCache)
5190     return(MagickFalse);
5191   if ((image->clip_mask != (Image *) NULL) &&
5192       (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5193     return(MagickFalse);
5194   if ((image->mask != (Image *) NULL) &&
5195       (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5196     return(MagickFalse);
5197   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5198     return(MagickTrue);
5199   assert(cache_info->signature == MagickSignature);
5200   status=WritePixelCachePixels(cache_info,nexus_info,exception);
5201   if ((cache_info->metacontent_extent != 0) &&
5202       (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5203     return(MagickFalse);
5204   return(status);
5205 }
5206 \f
5207 /*
5208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5209 %                                                                             %
5210 %                                                                             %
5211 %                                                                             %
5212 +   S y n c A u t h e n t i c P i x e l C a c h e                             %
5213 %                                                                             %
5214 %                                                                             %
5215 %                                                                             %
5216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5217 %
5218 %  SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5219 %  or disk cache.  The method returns MagickTrue if the pixel region is synced,
5220 %  otherwise MagickFalse.
5221 %
5222 %  The format of the SyncAuthenticPixelsCache() method is:
5223 %
5224 %      MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5225 %        ExceptionInfo *exception)
5226 %
5227 %  A description of each parameter follows:
5228 %
5229 %    o image: the image.
5230 %
5231 %    o exception: return any errors or warnings in this structure.
5232 %
5233 */
5234 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5235   ExceptionInfo *exception)
5236 {
5237   CacheInfo
5238     *cache_info;
5239
5240   const int
5241     id = GetOpenMPThreadId();
5242
5243   MagickBooleanType
5244     status;
5245
5246   assert(image != (Image *) NULL);
5247   assert(image->signature == MagickSignature);
5248   assert(image->cache != (Cache) NULL);
5249   cache_info=(CacheInfo *) image->cache;
5250   assert(cache_info->signature == MagickSignature);
5251   assert(id < (int) cache_info->number_threads);
5252   status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5253     exception);
5254   return(status);
5255 }
5256 \f
5257 /*
5258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5259 %                                                                             %
5260 %                                                                             %
5261 %                                                                             %
5262 %   S y n c A u t h e n t i c P i x e l s                                     %
5263 %                                                                             %
5264 %                                                                             %
5265 %                                                                             %
5266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5267 %
5268 %  SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5269 %  The method returns MagickTrue if the pixel region is flushed, otherwise
5270 %  MagickFalse.
5271 %
5272 %  The format of the SyncAuthenticPixels() method is:
5273 %
5274 %      MagickBooleanType SyncAuthenticPixels(Image *image,
5275 %        ExceptionInfo *exception)
5276 %
5277 %  A description of each parameter follows:
5278 %
5279 %    o image: the image.
5280 %
5281 %    o exception: return any errors or warnings in this structure.
5282 %
5283 */
5284 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5285   ExceptionInfo *exception)
5286 {
5287   CacheInfo
5288     *cache_info;
5289
5290   const int
5291     id = GetOpenMPThreadId();
5292
5293   MagickBooleanType
5294     status;
5295
5296   assert(image != (Image *) NULL);
5297   assert(image->signature == MagickSignature);
5298   assert(image->cache != (Cache) NULL);
5299   cache_info=(CacheInfo *) image->cache;
5300   assert(cache_info->signature == MagickSignature);
5301   if (cache_info->methods.sync_authentic_pixels_handler !=
5302        (SyncAuthenticPixelsHandler) NULL)
5303     {
5304       status=cache_info->methods.sync_authentic_pixels_handler(image,
5305         exception);
5306       return(status);
5307     }
5308   assert(id < (int) cache_info->number_threads);
5309   status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5310     exception);
5311   return(status);
5312 }
5313 \f
5314 /*
5315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5316 %                                                                             %
5317 %                                                                             %
5318 %                                                                             %
5319 +   S y n c I m a g e P i x e l C a c h e                                     %
5320 %                                                                             %
5321 %                                                                             %
5322 %                                                                             %
5323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5324 %
5325 %  SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5326 %  The method returns MagickTrue if the pixel region is flushed, otherwise
5327 %  MagickFalse.
5328 %
5329 %  The format of the SyncImagePixelCache() method is:
5330 %
5331 %      MagickBooleanType SyncImagePixelCache(Image *image,
5332 %        ExceptionInfo *exception)
5333 %
5334 %  A description of each parameter follows:
5335 %
5336 %    o image: the image.
5337 %
5338 %    o exception: return any errors or warnings in this structure.
5339 %
5340 */
5341 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5342   ExceptionInfo *exception)
5343 {
5344   CacheInfo
5345     *cache_info;
5346
5347   assert(image != (Image *) NULL);
5348   assert(exception != (ExceptionInfo *) NULL);
5349   cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5350   return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5351 }
5352 \f
5353 /*
5354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5355 %                                                                             %
5356 %                                                                             %
5357 %                                                                             %
5358 +   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                       %
5359 %                                                                             %
5360 %                                                                             %
5361 %                                                                             %
5362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5363 %
5364 %  WritePixelCacheMetacontent() writes the meta-content to the specified region
5365 %  of the pixel cache.
5366 %
5367 %  The format of the WritePixelCacheMetacontent() method is:
5368 %
5369 %      MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5370 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5371 %
5372 %  A description of each parameter follows:
5373 %
5374 %    o cache_info: the pixel cache.
5375 %
5376 %    o nexus_info: the cache nexus to write the meta-content.
5377 %
5378 %    o exception: return any errors or warnings in this structure.
5379 %
5380 */
5381 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5382   NexusInfo *nexus_info,ExceptionInfo *exception)
5383 {
5384   MagickOffsetType
5385     count,
5386     offset;
5387
5388   MagickSizeType
5389     extent,
5390     length;
5391
5392   register const unsigned char
5393     *restrict p;
5394
5395   register ssize_t
5396     y;
5397
5398   size_t
5399     rows;
5400
5401   if (cache_info->metacontent_extent == 0)
5402     return(MagickFalse);
5403   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5404     return(MagickTrue);
5405   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5406     nexus_info->region.x;
5407   length=(MagickSizeType) nexus_info->region.width*
5408     cache_info->metacontent_extent;
5409   rows=nexus_info->region.height;
5410   extent=(MagickSizeType) length*rows;
5411   p=(unsigned char *) nexus_info->metacontent;
5412   switch (cache_info->type)
5413   {
5414     case MemoryCache:
5415     case MapCache:
5416     {
5417       register unsigned char
5418         *restrict q;
5419
5420       /*
5421         Write associated pixels to memory.
5422       */
5423       if ((cache_info->columns == nexus_info->region.width) &&
5424           (extent == (MagickSizeType) ((size_t) extent)))
5425         {
5426           length=extent;
5427           rows=1UL;
5428         }
5429       q=(unsigned char *) cache_info->metacontent+offset*
5430         cache_info->metacontent_extent;
5431       for (y=0; y < (ssize_t) rows; y++)
5432       {
5433         (void) memcpy(q,p,(size_t) length);
5434         p+=nexus_info->region.width*cache_info->metacontent_extent;
5435         q+=cache_info->columns*cache_info->metacontent_extent;
5436       }
5437       break;
5438     }
5439     case DiskCache:
5440     {
5441       /*
5442         Write associated pixels to disk.
5443       */
5444       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5445         {
5446           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5447             cache_info->cache_filename);
5448           return(MagickFalse);
5449         }
5450       if ((cache_info->columns == nexus_info->region.width) &&
5451           (extent <= MagickMaxBufferExtent))
5452         {
5453           length=extent;
5454           rows=1UL;
5455         }
5456       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5457       for (y=0; y < (ssize_t) rows; y++)
5458       {
5459         count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5460           cache_info->number_channels*sizeof(Quantum)+offset*
5461           cache_info->metacontent_extent,length,(const unsigned char *) p);
5462         if ((MagickSizeType) count != length)
5463           break;
5464         p+=nexus_info->region.width*cache_info->metacontent_extent;
5465         offset+=cache_info->columns;
5466       }
5467       if (y < (ssize_t) rows)
5468         {
5469           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5470             cache_info->cache_filename);
5471           return(MagickFalse);
5472         }
5473       break;
5474     }
5475     default:
5476       break;
5477   }
5478   if ((cache_info->debug != MagickFalse) &&
5479       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5480     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5481       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5482       nexus_info->region.width,(double) nexus_info->region.height,(double)
5483       nexus_info->region.x,(double) nexus_info->region.y);
5484   return(MagickTrue);
5485 }
5486 \f
5487 /*
5488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5489 %                                                                             %
5490 %                                                                             %
5491 %                                                                             %
5492 +   W r i t e C a c h e P i x e l s                                           %
5493 %                                                                             %
5494 %                                                                             %
5495 %                                                                             %
5496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5497 %
5498 %  WritePixelCachePixels() writes image pixels to the specified region of the
5499 %  pixel cache.
5500 %
5501 %  The format of the WritePixelCachePixels() method is:
5502 %
5503 %      MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5504 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5505 %
5506 %  A description of each parameter follows:
5507 %
5508 %    o cache_info: the pixel cache.
5509 %
5510 %    o nexus_info: the cache nexus to write the pixels.
5511 %
5512 %    o exception: return any errors or warnings in this structure.
5513 %
5514 */
5515 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5516   NexusInfo *nexus_info,ExceptionInfo *exception)
5517 {
5518   MagickOffsetType
5519     count,
5520     offset;
5521
5522   MagickSizeType
5523     extent,
5524     length;
5525
5526   register const Quantum
5527     *restrict p;
5528
5529   register ssize_t
5530     y;
5531
5532   size_t
5533     rows;
5534
5535   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5536     return(MagickTrue);
5537   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5538     nexus_info->region.x;
5539   length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5540     sizeof(Quantum);
5541   rows=nexus_info->region.height;
5542   extent=length*rows;
5543   p=nexus_info->pixels;
5544   switch (cache_info->type)
5545   {
5546     case MemoryCache:
5547     case MapCache:
5548     {
5549       register Quantum
5550         *restrict q;
5551
5552       /*
5553         Write pixels to memory.
5554       */
5555       if ((cache_info->columns == nexus_info->region.width) &&
5556           (extent == (MagickSizeType) ((size_t) extent)))
5557         {
5558           length=extent;
5559           rows=1UL;
5560         }
5561       q=cache_info->pixels+offset*cache_info->number_channels;
5562       for (y=0; y < (ssize_t) rows; y++)
5563       {
5564         (void) memcpy(q,p,(size_t) length);
5565         p+=nexus_info->region.width*cache_info->number_channels;
5566         q+=cache_info->columns*cache_info->number_channels;
5567       }
5568       break;
5569     }
5570     case DiskCache:
5571     {
5572       /*
5573         Write pixels to disk.
5574       */
5575       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5576         {
5577           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5578             cache_info->cache_filename);
5579           return(MagickFalse);
5580         }
5581       if ((cache_info->columns == nexus_info->region.width) &&
5582           (extent <= MagickMaxBufferExtent))
5583         {
5584           length=extent;
5585           rows=1UL;
5586         }
5587       for (y=0; y < (ssize_t) rows; y++)
5588       {
5589         count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5590           cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5591           p);
5592         if ((MagickSizeType) count != length)
5593           break;
5594         p+=nexus_info->region.width*cache_info->number_channels;
5595         offset+=cache_info->columns;
5596       }
5597       if (y < (ssize_t) rows)
5598         {
5599           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5600             cache_info->cache_filename);
5601           return(MagickFalse);
5602         }
5603       break;
5604     }
5605     default:
5606       break;
5607   }
5608   if ((cache_info->debug != MagickFalse) &&
5609       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5610     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5611       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5612       nexus_info->region.width,(double) nexus_info->region.height,(double)
5613       nexus_info->region.x,(double) nexus_info->region.y);
5614   return(MagickTrue);
5615 }