]> 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-2012 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 P i x e l                                       %
2246 %                                                                             %
2247 %                                                                             %
2248 %                                                                             %
2249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2250 %
2251 %  GetOneVirtualPixel() returns a single virtual pixel at the specified
2252 %  (x,y) location.  The image background color is returned if an error occurs.
2253 %  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2254 %
2255 %  The format of the GetOneVirtualPixel() method is:
2256 %
2257 %      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2258 %        const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2259 %
2260 %  A description of each parameter follows:
2261 %
2262 %    o image: the image.
2263 %
2264 %    o x,y:  These values define the location of the pixel to return.
2265 %
2266 %    o pixel: return a pixel at the specified (x,y) location.
2267 %
2268 %    o exception: return any errors or warnings in this structure.
2269 %
2270 */
2271 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2272   const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2273 {
2274   CacheInfo
2275     *cache_info;
2276
2277   const int
2278     id = GetOpenMPThreadId();
2279
2280   const Quantum
2281     *p;
2282
2283   register ssize_t
2284     i;
2285
2286   assert(image != (const Image *) NULL);
2287   assert(image->signature == MagickSignature);
2288   assert(image->cache != (Cache) NULL);
2289   cache_info=(CacheInfo *) image->cache;
2290   assert(cache_info->signature == MagickSignature);
2291   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2292   if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2293        (GetOneVirtualPixelFromHandler) NULL)
2294     return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2295       GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2296   assert(id < (int) cache_info->number_threads);
2297   p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2298     1UL,1UL,cache_info->nexus_info[id],exception);
2299   if (p == (const Quantum *) NULL)
2300     {
2301       pixel[RedPixelChannel]=image->background_color.red;
2302       pixel[GreenPixelChannel]=image->background_color.green;
2303       pixel[BluePixelChannel]=image->background_color.blue;
2304       pixel[BlackPixelChannel]=image->background_color.black;
2305       pixel[AlphaPixelChannel]=image->background_color.alpha;
2306       return(MagickFalse);
2307     }
2308   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2309   {
2310     PixelChannel
2311       channel;
2312
2313     channel=GetPixelChannelMapChannel(image,i);
2314     pixel[channel]=p[i];
2315   }
2316   return(MagickTrue);
2317 }
2318 \f
2319 /*
2320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2321 %                                                                             %
2322 %                                                                             %
2323 %                                                                             %
2324 +   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                     %
2325 %                                                                             %
2326 %                                                                             %
2327 %                                                                             %
2328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2329 %
2330 %  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2331 %  specified (x,y) location.  The image background color is returned if an
2332 %  error occurs.
2333 %
2334 %  The format of the GetOneVirtualPixelFromCache() method is:
2335 %
2336 %      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2337 %        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2338 %        Quantum *pixel,ExceptionInfo *exception)
2339 %
2340 %  A description of each parameter follows:
2341 %
2342 %    o image: the image.
2343 %
2344 %    o virtual_pixel_method: the virtual pixel method.
2345 %
2346 %    o x,y:  These values define the location of the pixel to return.
2347 %
2348 %    o pixel: return a pixel at the specified (x,y) location.
2349 %
2350 %    o exception: return any errors or warnings in this structure.
2351 %
2352 */
2353 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2354   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2355   Quantum *pixel,ExceptionInfo *exception)
2356 {
2357   CacheInfo
2358     *cache_info;
2359
2360   const int
2361     id = GetOpenMPThreadId();
2362
2363   const Quantum
2364     *p;
2365
2366   register ssize_t
2367     i;
2368
2369   assert(image != (const Image *) NULL);
2370   assert(image->signature == MagickSignature);
2371   assert(image->cache != (Cache) NULL);
2372   cache_info=(CacheInfo *) image->cache;
2373   assert(cache_info->signature == MagickSignature);
2374   assert(id < (int) cache_info->number_threads);
2375   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2376   p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2377     cache_info->nexus_info[id],exception);
2378   if (p == (const Quantum *) NULL)
2379     {
2380       pixel[RedPixelChannel]=image->background_color.red;
2381       pixel[GreenPixelChannel]=image->background_color.green;
2382       pixel[BluePixelChannel]=image->background_color.blue;
2383       pixel[BlackPixelChannel]=image->background_color.black;
2384       pixel[AlphaPixelChannel]=image->background_color.alpha;
2385       return(MagickFalse);
2386     }
2387   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2388   {
2389     PixelChannel
2390       channel;
2391
2392     channel=GetPixelChannelMapChannel(image,i);
2393     pixel[channel]=p[i];
2394   }
2395   return(MagickTrue);
2396 }
2397 \f
2398 /*
2399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2400 %                                                                             %
2401 %                                                                             %
2402 %                                                                             %
2403 %   G e t O n e V i r t u a l P i x e l I n f o                               %
2404 %                                                                             %
2405 %                                                                             %
2406 %                                                                             %
2407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2408 %
2409 %  GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2410 %  location.  The image background color is returned if an error occurs.  If
2411 %  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2412 %
2413 %  The format of the GetOneVirtualPixelInfo() method is:
2414 %
2415 %      MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2416 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2417 %        const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2418 %
2419 %  A description of each parameter follows:
2420 %
2421 %    o image: the image.
2422 %
2423 %    o virtual_pixel_method: the virtual pixel method.
2424 %
2425 %    o x,y:  these values define the location of the pixel to return.
2426 %
2427 %    o pixel: return a pixel at the specified (x,y) location.
2428 %
2429 %    o exception: return any errors or warnings in this structure.
2430 %
2431 */
2432 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2433   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2434   PixelInfo *pixel,ExceptionInfo *exception)
2435 {
2436   CacheInfo
2437     *cache_info;
2438
2439   const int
2440     id = GetOpenMPThreadId();
2441
2442   register const Quantum
2443     *p;
2444
2445   assert(image != (const Image *) NULL);
2446   assert(image->signature == MagickSignature);
2447   assert(image->cache != (Cache) NULL);
2448   cache_info=(CacheInfo *) image->cache;
2449   assert(cache_info->signature == MagickSignature);
2450   assert(id < (int) cache_info->number_threads);
2451   p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2452     cache_info->nexus_info[id],exception);
2453   GetPixelInfo(image,pixel);
2454   if (p == (const Quantum *) NULL)
2455     return(MagickFalse);
2456   GetPixelInfoPixel(image,p,pixel);
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 MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3790   const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
3791 {
3792   MagickRealType
3793     gamma;
3794
3795   if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
3796     {
3797       *composite=(*q);
3798       return;
3799     }
3800   gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3801   gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3802   composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3803   composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3804   composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3805   if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3806     composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
3807 }
3808
3809 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3810   ExceptionInfo *exception)
3811 {
3812   CacheInfo
3813     *cache_info;
3814
3815   PixelInfo
3816     alpha,
3817     beta;
3818
3819   MagickSizeType
3820     number_pixels;
3821
3822   NexusInfo
3823     **clip_nexus,
3824     **image_nexus;
3825
3826   register const Quantum
3827     *restrict p,
3828     *restrict r;
3829
3830   register Quantum
3831     *restrict q;
3832
3833   register ssize_t
3834     i;
3835
3836   /*
3837     Apply clip mask.
3838   */
3839   if (image->debug != MagickFalse)
3840     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3841   if (image->mask == (Image *) NULL)
3842     return(MagickFalse);
3843   cache_info=(CacheInfo *) image->cache;
3844   if (cache_info == (Cache) NULL)
3845     return(MagickFalse);
3846   image_nexus=AcquirePixelCacheNexus(1);
3847   clip_nexus=AcquirePixelCacheNexus(1);
3848   if ((image_nexus == (NexusInfo **) NULL) ||
3849       (clip_nexus == (NexusInfo **) NULL))
3850     ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3851   p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3852     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3853     nexus_info->region.height,image_nexus[0],exception);
3854   q=nexus_info->pixels;
3855   r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3856     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3857     nexus_info->region.height,clip_nexus[0],exception);
3858   GetPixelInfo(image,&alpha);
3859   GetPixelInfo(image,&beta);
3860   number_pixels=(MagickSizeType) nexus_info->region.width*
3861     nexus_info->region.height;
3862   for (i=0; i < (ssize_t) number_pixels; i++)
3863   {
3864     if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
3865       break;
3866     GetPixelInfoPixel(image,p,&alpha);
3867     GetPixelInfoPixel(image,q,&beta);
3868     MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
3869       &alpha,alpha.alpha,&beta);
3870     SetPixelRed(image,ClampToQuantum(beta.red),q);
3871     SetPixelGreen(image,ClampToQuantum(beta.green),q);
3872     SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3873     if (cache_info->colorspace == CMYKColorspace)
3874       SetPixelBlack(image,ClampToQuantum(beta.black),q);
3875     SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
3876     p++;
3877     q++;
3878     r++;
3879   }
3880   clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3881   image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3882   if (i < (ssize_t) number_pixels)
3883     return(MagickFalse);
3884   return(MagickTrue);
3885 }
3886 \f
3887 /*
3888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3889 %                                                                             %
3890 %                                                                             %
3891 %                                                                             %
3892 +   O p e n P i x e l C a c h e                                               %
3893 %                                                                             %
3894 %                                                                             %
3895 %                                                                             %
3896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3897 %
3898 %  OpenPixelCache() allocates the pixel cache.  This includes defining the cache
3899 %  dimensions, allocating space for the image pixels and optionally the
3900 %  metacontent, and memory mapping the cache if it is disk based.  The cache
3901 %  nexus array is initialized as well.
3902 %
3903 %  The format of the OpenPixelCache() method is:
3904 %
3905 %      MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3906 %        ExceptionInfo *exception)
3907 %
3908 %  A description of each parameter follows:
3909 %
3910 %    o image: the image.
3911 %
3912 %    o mode: ReadMode, WriteMode, or IOMode.
3913 %
3914 %    o exception: return any errors or warnings in this structure.
3915 %
3916 */
3917
3918 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3919 {
3920   cache_info->mapped=MagickFalse;
3921   cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3922     cache_info->length);
3923   if (cache_info->pixels == (Quantum *) NULL)
3924     {
3925       cache_info->mapped=MagickTrue;
3926       cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3927         cache_info->length);
3928     }
3929 }
3930
3931 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3932 {
3933   CacheInfo
3934     *cache_info;
3935
3936   MagickOffsetType
3937     count,
3938     extent,
3939     offset;
3940
3941   cache_info=(CacheInfo *) image->cache;
3942   if (image->debug != MagickFalse)
3943     {
3944       char
3945         format[MaxTextExtent],
3946         message[MaxTextExtent];
3947
3948       (void) FormatMagickSize(length,MagickFalse,format);
3949       (void) FormatLocaleString(message,MaxTextExtent,
3950         "extend %s (%s[%d], disk, %s)",cache_info->filename,
3951         cache_info->cache_filename,cache_info->file,format);
3952       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3953     }
3954   if (length != (MagickSizeType) ((MagickOffsetType) length))
3955     return(MagickFalse);
3956   extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3957   if (extent < 0)
3958     return(MagickFalse);
3959   if ((MagickSizeType) extent >= length)
3960     return(MagickTrue);
3961   offset=(MagickOffsetType) length-1;
3962   count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3963   return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3964 }
3965
3966 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3967   ExceptionInfo *exception)
3968 {
3969   CacheInfo
3970     *cache_info,
3971     source_info;
3972
3973   char
3974     format[MaxTextExtent],
3975     message[MaxTextExtent];
3976
3977   MagickBooleanType
3978     status;
3979
3980   MagickSizeType
3981     length,
3982     number_pixels;
3983
3984   size_t
3985     columns,
3986     packet_size;
3987
3988   assert(image != (const Image *) NULL);
3989   assert(image->signature == MagickSignature);
3990   assert(image->cache != (Cache) NULL);
3991   if (image->debug != MagickFalse)
3992     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3993   if ((image->columns == 0) || (image->rows == 0))
3994     ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3995   cache_info=(CacheInfo *) image->cache;
3996   assert(cache_info->signature == MagickSignature);
3997   source_info=(*cache_info);
3998   source_info.file=(-1);
3999   (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4000     image->filename,(double) GetImageIndexInList(image));
4001   cache_info->storage_class=image->storage_class;
4002   cache_info->colorspace=image->colorspace;
4003   cache_info->matte=image->matte;
4004   cache_info->rows=image->rows;
4005   cache_info->columns=image->columns;
4006   InitializePixelChannelMap(image);
4007   cache_info->number_channels=GetPixelChannels(image);
4008   cache_info->metacontent_extent=image->metacontent_extent;
4009   cache_info->mode=mode;
4010   if (image->ping != MagickFalse)
4011     {
4012       cache_info->type=PingCache;
4013       cache_info->pixels=(Quantum *) NULL;
4014       cache_info->metacontent=(void *) NULL;
4015       cache_info->length=0;
4016       return(MagickTrue);
4017     }
4018   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4019   packet_size=cache_info->number_channels*sizeof(Quantum);
4020   if (image->metacontent_extent != 0)
4021     packet_size+=cache_info->metacontent_extent;
4022   length=number_pixels*packet_size;
4023   columns=(size_t) (length/cache_info->rows/packet_size);
4024   if (cache_info->columns != columns)
4025     ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4026       image->filename);
4027   cache_info->length=length;
4028   if ((cache_info->type != UndefinedCache) &&
4029       (cache_info->columns <= source_info.columns) &&
4030       (cache_info->rows <= source_info.rows) &&
4031       (cache_info->number_channels <= source_info.number_channels) &&
4032       (cache_info->metacontent_extent <= source_info.metacontent_extent))
4033     {
4034       /*
4035         Inline pixel cache clone optimization.
4036       */
4037       if ((cache_info->columns == source_info.columns) &&
4038           (cache_info->rows == source_info.rows) &&
4039           (cache_info->number_channels == source_info.number_channels) &&
4040           (cache_info->metacontent_extent == source_info.metacontent_extent))
4041         return(MagickTrue);
4042       return(ClonePixelCachePixels(cache_info,&source_info,exception));
4043     }
4044   status=AcquireMagickResource(AreaResource,cache_info->length);
4045   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4046     cache_info->metacontent_extent);
4047   if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4048     {
4049       status=AcquireMagickResource(MemoryResource,cache_info->length);
4050       if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4051           (cache_info->type == MemoryCache))
4052         {
4053           AllocatePixelCachePixels(cache_info);
4054           if (cache_info->pixels == (Quantum *) NULL)
4055             cache_info->pixels=source_info.pixels;
4056           else
4057             {
4058               /*
4059                 Create memory pixel cache.
4060               */
4061               status=MagickTrue;
4062               if (image->debug != MagickFalse)
4063                 {
4064                   (void) FormatMagickSize(cache_info->length,MagickTrue,
4065                     format);
4066                   (void) FormatLocaleString(message,MaxTextExtent,
4067                     "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4068                     cache_info->filename,cache_info->mapped != MagickFalse ?
4069                     "anonymous" : "heap",(double) cache_info->columns,(double)
4070                     cache_info->rows,(double) cache_info->number_channels,
4071                     format);
4072                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4073                     message);
4074                 }
4075               cache_info->type=MemoryCache;
4076               cache_info->metacontent=(void *) NULL;
4077               if (cache_info->metacontent_extent != 0)
4078                 cache_info->metacontent=(void *) (cache_info->pixels+
4079                   number_pixels*cache_info->number_channels);
4080               if (source_info.storage_class != UndefinedClass)
4081                 {
4082                   status=ClonePixelCachePixels(cache_info,&source_info,
4083                     exception);
4084                   RelinquishPixelCachePixels(&source_info);
4085                 }
4086               return(status);
4087             }
4088         }
4089       RelinquishMagickResource(MemoryResource,cache_info->length);
4090     }
4091   /*
4092     Create pixel cache on disk.
4093   */
4094   status=AcquireMagickResource(DiskResource,cache_info->length);
4095   if (status == MagickFalse)
4096     {
4097       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4098         "CacheResourcesExhausted","`%s'",image->filename);
4099       return(MagickFalse);
4100     }
4101   if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4102     {
4103       RelinquishMagickResource(DiskResource,cache_info->length);
4104       ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4105         image->filename);
4106       return(MagickFalse);
4107     }
4108   status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4109     cache_info->length);
4110   if (status == MagickFalse)
4111     {
4112       ThrowFileException(exception,CacheError,"UnableToExtendCache",
4113         image->filename);
4114       return(MagickFalse);
4115     }
4116   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4117     cache_info->metacontent_extent);
4118   if (length != (MagickSizeType) ((size_t) length))
4119     cache_info->type=DiskCache;
4120   else
4121     {
4122       status=AcquireMagickResource(MapResource,cache_info->length);
4123       if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4124           (cache_info->type != MemoryCache))
4125         cache_info->type=DiskCache;
4126       else
4127         {
4128           cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4129             cache_info->offset,(size_t) cache_info->length);
4130           if (cache_info->pixels == (Quantum *) NULL)
4131             {
4132               cache_info->type=DiskCache;
4133               cache_info->pixels=source_info.pixels;
4134             }
4135           else
4136             {
4137               /*
4138                 Create file-backed memory-mapped pixel cache.
4139               */
4140               status=MagickTrue;
4141               (void) ClosePixelCacheOnDisk(cache_info);
4142               cache_info->type=MapCache;
4143               cache_info->mapped=MagickTrue;
4144               cache_info->metacontent=(void *) NULL;
4145               if (cache_info->metacontent_extent != 0)
4146                 cache_info->metacontent=(void *) (cache_info->pixels+
4147                   number_pixels*cache_info->number_channels);
4148               if (source_info.storage_class != UndefinedClass)
4149                 {
4150                   status=ClonePixelCachePixels(cache_info,&source_info,
4151                     exception);
4152                   RelinquishPixelCachePixels(&source_info);
4153                 }
4154               if (image->debug != MagickFalse)
4155                 {
4156                   (void) FormatMagickSize(cache_info->length,MagickTrue,
4157                     format);
4158                   (void) FormatLocaleString(message,MaxTextExtent,
4159                     "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4160                     cache_info->filename,cache_info->cache_filename,
4161                     cache_info->file,(double) cache_info->columns,(double)
4162                     cache_info->rows,(double) cache_info->number_channels,
4163                     format);
4164                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4165                     message);
4166                 }
4167               return(status);
4168             }
4169         }
4170       RelinquishMagickResource(MapResource,cache_info->length);
4171     }
4172   status=MagickTrue;
4173   if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4174     {
4175       status=ClonePixelCachePixels(cache_info,&source_info,exception);
4176       RelinquishPixelCachePixels(&source_info);
4177     }
4178   if (image->debug != MagickFalse)
4179     {
4180       (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4181       (void) FormatLocaleString(message,MaxTextExtent,
4182         "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4183         cache_info->cache_filename,cache_info->file,(double)
4184         cache_info->columns,(double) cache_info->rows,(double)
4185         cache_info->number_channels,format);
4186       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4187     }
4188   return(status);
4189 }
4190 \f
4191 /*
4192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4193 %                                                                             %
4194 %                                                                             %
4195 %                                                                             %
4196 +   P e r s i s t P i x e l C a c h e                                         %
4197 %                                                                             %
4198 %                                                                             %
4199 %                                                                             %
4200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4201 %
4202 %  PersistPixelCache() attaches to or initializes a persistent pixel cache.  A
4203 %  persistent pixel cache is one that resides on disk and is not destroyed
4204 %  when the program exits.
4205 %
4206 %  The format of the PersistPixelCache() method is:
4207 %
4208 %      MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4209 %        const MagickBooleanType attach,MagickOffsetType *offset,
4210 %        ExceptionInfo *exception)
4211 %
4212 %  A description of each parameter follows:
4213 %
4214 %    o image: the image.
4215 %
4216 %    o filename: the persistent pixel cache filename.
4217 %
4218 %    o attach: A value other than zero initializes the persistent pixel cache.
4219 %
4220 %    o initialize: A value other than zero initializes the persistent pixel
4221 %      cache.
4222 %
4223 %    o offset: the offset in the persistent cache to store pixels.
4224 %
4225 %    o exception: return any errors or warnings in this structure.
4226 %
4227 */
4228 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4229   const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4230   ExceptionInfo *exception)
4231 {
4232   CacheInfo
4233     *cache_info,
4234     *clone_info;
4235
4236   Image
4237     clone_image;
4238
4239   MagickBooleanType
4240     status;
4241
4242   ssize_t
4243     page_size;
4244
4245   assert(image != (Image *) NULL);
4246   assert(image->signature == MagickSignature);
4247   if (image->debug != MagickFalse)
4248     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4249   assert(image->cache != (void *) NULL);
4250   assert(filename != (const char *) NULL);
4251   assert(offset != (MagickOffsetType *) NULL);
4252   page_size=GetMagickPageSize();
4253   cache_info=(CacheInfo *) image->cache;
4254   assert(cache_info->signature == MagickSignature);
4255   if (attach != MagickFalse)
4256     {
4257       /*
4258         Attach existing persistent pixel cache.
4259       */
4260       if (image->debug != MagickFalse)
4261         (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4262           "attach persistent cache");
4263       (void) CopyMagickString(cache_info->cache_filename,filename,
4264         MaxTextExtent);
4265       cache_info->type=DiskCache;
4266       cache_info->offset=(*offset);
4267       if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4268         return(MagickFalse);
4269       *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4270       return(MagickTrue);
4271     }
4272   if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4273       (cache_info->reference_count == 1))
4274     {
4275       LockSemaphoreInfo(cache_info->semaphore);
4276       if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4277           (cache_info->reference_count == 1))
4278         {
4279           int
4280             status;
4281
4282           /*
4283             Usurp existing persistent pixel cache.
4284           */
4285           status=rename_utf8(cache_info->cache_filename,filename);
4286           if (status == 0)
4287             {
4288               (void) CopyMagickString(cache_info->cache_filename,filename,
4289                 MaxTextExtent);
4290               *offset+=cache_info->length+page_size-(cache_info->length %
4291                 page_size);
4292               UnlockSemaphoreInfo(cache_info->semaphore);
4293               cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4294               if (image->debug != MagickFalse)
4295                 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4296                   "Usurp resident persistent cache");
4297               return(MagickTrue);
4298             }
4299         }
4300       UnlockSemaphoreInfo(cache_info->semaphore);
4301     }
4302   /*
4303     Clone persistent pixel cache.
4304   */
4305   clone_image=(*image);
4306   clone_info=(CacheInfo *) clone_image.cache;
4307   image->cache=ClonePixelCache(cache_info);
4308   cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4309   (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4310   cache_info->type=DiskCache;
4311   cache_info->offset=(*offset);
4312   cache_info=(CacheInfo *) image->cache;
4313   status=OpenPixelCache(image,IOMode,exception);
4314   if (status != MagickFalse)
4315     status=ClonePixelCachePixels(cache_info,clone_info,exception);
4316   *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4317   clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4318   return(status);
4319 }
4320 \f
4321 /*
4322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4323 %                                                                             %
4324 %                                                                             %
4325 %                                                                             %
4326 +   Q u e u e A u t h e n t i c N e x u s                                     %
4327 %                                                                             %
4328 %                                                                             %
4329 %                                                                             %
4330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4331 %
4332 %  QueueAuthenticNexus() allocates an region to store image pixels as defined
4333 %  by the region rectangle and returns a pointer to the region.  This region is
4334 %  subsequently transferred from the pixel cache with
4335 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4336 %  pixels are transferred, otherwise a NULL is returned.
4337 %
4338 %  The format of the QueueAuthenticNexus() method is:
4339 %
4340 %      Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4341 %        const ssize_t y,const size_t columns,const size_t rows,
4342 %        const MagickBooleanType clone,NexusInfo *nexus_info,
4343 %        ExceptionInfo *exception)
4344 %
4345 %  A description of each parameter follows:
4346 %
4347 %    o image: the image.
4348 %
4349 %    o x,y,columns,rows:  These values define the perimeter of a region of
4350 %      pixels.
4351 %
4352 %    o nexus_info: the cache nexus to set.
4353 %
4354 %    o clone: clone the pixel cache.
4355 %
4356 %    o exception: return any errors or warnings in this structure.
4357 %
4358 */
4359 MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4360   const ssize_t y,const size_t columns,const size_t rows,
4361   const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4362 {
4363   CacheInfo
4364     *cache_info;
4365
4366   MagickOffsetType
4367     offset;
4368
4369   MagickSizeType
4370     number_pixels;
4371
4372   RectangleInfo
4373     region;
4374
4375   /*
4376     Validate pixel cache geometry.
4377   */
4378   assert(image != (const Image *) NULL);
4379   assert(image->signature == MagickSignature);
4380   assert(image->cache != (Cache) NULL);
4381   cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4382   if (cache_info == (Cache) NULL)
4383     return((Quantum *) NULL);
4384   assert(cache_info->signature == MagickSignature);
4385   if ((cache_info->columns == 0) && (cache_info->rows == 0))
4386     {
4387       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4388         "NoPixelsDefinedInCache","`%s'",image->filename);
4389       return((Quantum *) NULL);
4390     }
4391   if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4392       (y >= (ssize_t) cache_info->rows))
4393     {
4394       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4395         "PixelsAreNotAuthentic","`%s'",image->filename);
4396       return((Quantum *) NULL);
4397     }
4398   offset=(MagickOffsetType) y*cache_info->columns+x;
4399   if (offset < 0)
4400     return((Quantum *) NULL);
4401   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4402   offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4403   if ((MagickSizeType) offset >= number_pixels)
4404     return((Quantum *) NULL);
4405   /*
4406     Return pixel cache.
4407   */
4408   region.x=x;
4409   region.y=y;
4410   region.width=columns;
4411   region.height=rows;
4412   return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4413 }
4414 \f
4415 /*
4416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4417 %                                                                             %
4418 %                                                                             %
4419 %                                                                             %
4420 +   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                         %
4421 %                                                                             %
4422 %                                                                             %
4423 %                                                                             %
4424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4425 %
4426 %  QueueAuthenticPixelsCache() allocates an region to store image pixels as
4427 %  defined by the region rectangle and returns a pointer to the region.  This
4428 %  region is subsequently transferred from the pixel cache with
4429 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4430 %  pixels are transferred, otherwise a NULL is returned.
4431 %
4432 %  The format of the QueueAuthenticPixelsCache() method is:
4433 %
4434 %      Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4435 %        const ssize_t y,const size_t columns,const size_t rows,
4436 %        ExceptionInfo *exception)
4437 %
4438 %  A description of each parameter follows:
4439 %
4440 %    o image: the image.
4441 %
4442 %    o x,y,columns,rows:  These values define the perimeter of a region of
4443 %      pixels.
4444 %
4445 %    o exception: return any errors or warnings in this structure.
4446 %
4447 */
4448 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4449   const ssize_t y,const size_t columns,const size_t rows,
4450   ExceptionInfo *exception)
4451 {
4452   CacheInfo
4453     *cache_info;
4454
4455   const int
4456     id = GetOpenMPThreadId();
4457
4458   Quantum
4459     *q;
4460
4461   assert(image != (const Image *) NULL);
4462   assert(image->signature == MagickSignature);
4463   assert(image->cache != (Cache) NULL);
4464   cache_info=(CacheInfo *) image->cache;
4465   assert(cache_info->signature == MagickSignature);
4466   assert(id < (int) cache_info->number_threads);
4467   q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4468     cache_info->nexus_info[id],exception);
4469   return(q);
4470 }
4471 \f
4472 /*
4473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4474 %                                                                             %
4475 %                                                                             %
4476 %                                                                             %
4477 %   Q u e u e A u t h e n t i c P i x e l s                                   %
4478 %                                                                             %
4479 %                                                                             %
4480 %                                                                             %
4481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4482 %
4483 %  QueueAuthenticPixels() queues a mutable pixel region.  If the region is
4484 %  successfully initialized a pointer to a Quantum array representing the
4485 %  region is returned, otherwise NULL is returned.  The returned pointer may
4486 %  point to a temporary working buffer for the pixels or it may point to the
4487 %  final location of the pixels in memory.
4488 %
4489 %  Write-only access means that any existing pixel values corresponding to
4490 %  the region are ignored.  This is useful if the initial image is being
4491 %  created from scratch, or if the existing pixel values are to be
4492 %  completely replaced without need to refer to their pre-existing values.
4493 %  The application is free to read and write the pixel buffer returned by
4494 %  QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4495 %  initialize the pixel array values. Initializing pixel array values is the
4496 %  application's responsibility.
4497 %
4498 %  Performance is maximized if the selected region is part of one row, or
4499 %  one or more full rows, since then there is opportunity to access the
4500 %  pixels in-place (without a copy) if the image is in memory, or in a
4501 %  memory-mapped file. The returned pointer must *never* be deallocated
4502 %  by the user.
4503 %
4504 %  Pixels accessed via the returned pointer represent a simple array of type
4505 %  Quantum. If the image type is CMYK or the storage class is PseudoClass,
4506 %  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4507 %  obtain the meta-content (of type void) corresponding to the region.
4508 %  Once the Quantum (and/or Quantum) array has been updated, the
4509 %  changes must be saved back to the underlying image using
4510 %  SyncAuthenticPixels() or they may be lost.
4511 %
4512 %  The format of the QueueAuthenticPixels() method is:
4513 %
4514 %      Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4515 %        const ssize_t y,const size_t columns,const size_t rows,
4516 %        ExceptionInfo *exception)
4517 %
4518 %  A description of each parameter follows:
4519 %
4520 %    o image: the image.
4521 %
4522 %    o x,y,columns,rows:  These values define the perimeter of a region of
4523 %      pixels.
4524 %
4525 %    o exception: return any errors or warnings in this structure.
4526 %
4527 */
4528 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4529   const ssize_t y,const size_t columns,const size_t rows,
4530   ExceptionInfo *exception)
4531 {
4532   CacheInfo
4533     *cache_info;
4534
4535   const int
4536     id = GetOpenMPThreadId();
4537
4538   Quantum
4539     *q;
4540
4541   assert(image != (Image *) NULL);
4542   assert(image->signature == MagickSignature);
4543   assert(image->cache != (Cache) NULL);
4544   cache_info=(CacheInfo *) image->cache;
4545   assert(cache_info->signature == MagickSignature);
4546   if (cache_info->methods.queue_authentic_pixels_handler !=
4547        (QueueAuthenticPixelsHandler) NULL)
4548     {
4549       q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4550         columns,rows,exception);
4551       return(q);
4552     }
4553   assert(id < (int) cache_info->number_threads);
4554   q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4555     cache_info->nexus_info[id],exception);
4556   return(q);
4557 }
4558 \f
4559 /*
4560 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4561 %                                                                             %
4562 %                                                                             %
4563 %                                                                             %
4564 +   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                         %
4565 %                                                                             %
4566 %                                                                             %
4567 %                                                                             %
4568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4569 %
4570 %  ReadPixelCacheMetacontent() reads metacontent from the specified region of
4571 %  the pixel cache.
4572 %
4573 %  The format of the ReadPixelCacheMetacontent() method is:
4574 %
4575 %      MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4576 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4577 %
4578 %  A description of each parameter follows:
4579 %
4580 %    o cache_info: the pixel cache.
4581 %
4582 %    o nexus_info: the cache nexus to read the metacontent.
4583 %
4584 %    o exception: return any errors or warnings in this structure.
4585 %
4586 */
4587 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4588   NexusInfo *nexus_info,ExceptionInfo *exception)
4589 {
4590   MagickOffsetType
4591     count,
4592     offset;
4593
4594   MagickSizeType
4595     extent,
4596     length;
4597
4598   register ssize_t
4599     y;
4600
4601   register unsigned char
4602     *restrict q;
4603
4604   size_t
4605     rows;
4606
4607   if (cache_info->metacontent_extent == 0)
4608     return(MagickFalse);
4609   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4610     return(MagickTrue);
4611   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4612     nexus_info->region.x;
4613   length=(MagickSizeType) nexus_info->region.width*
4614     cache_info->metacontent_extent;
4615   rows=nexus_info->region.height;
4616   extent=length*rows;
4617   q=(unsigned char *) nexus_info->metacontent;
4618   switch (cache_info->type)
4619   {
4620     case MemoryCache:
4621     case MapCache:
4622     {
4623       register unsigned char
4624         *restrict p;
4625
4626       /*
4627         Read meta-content from memory.
4628       */
4629       if ((cache_info->columns == nexus_info->region.width) &&
4630           (extent == (MagickSizeType) ((size_t) extent)))
4631         {
4632           length=extent;
4633           rows=1UL;
4634         }
4635       p=(unsigned char *) cache_info->metacontent+offset*
4636         cache_info->metacontent_extent;
4637       for (y=0; y < (ssize_t) rows; y++)
4638       {
4639         (void) memcpy(q,p,(size_t) length);
4640         p+=cache_info->metacontent_extent*cache_info->columns;
4641         q+=cache_info->metacontent_extent*nexus_info->region.width;
4642       }
4643       break;
4644     }
4645     case DiskCache:
4646     {
4647       /*
4648         Read meta content from disk.
4649       */
4650       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4651         {
4652           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4653             cache_info->cache_filename);
4654           return(MagickFalse);
4655         }
4656       if ((cache_info->columns == nexus_info->region.width) &&
4657           (extent <= MagickMaxBufferExtent))
4658         {
4659           length=extent;
4660           rows=1UL;
4661         }
4662       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4663       for (y=0; y < (ssize_t) rows; y++)
4664       {
4665         count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4666           cache_info->number_channels*sizeof(Quantum)+offset*
4667           cache_info->metacontent_extent,length,(unsigned char *) q);
4668         if ((MagickSizeType) count != length)
4669           break;
4670         offset+=cache_info->columns;
4671         q+=cache_info->metacontent_extent*nexus_info->region.width;
4672       }
4673       if (y < (ssize_t) rows)
4674         {
4675           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4676             cache_info->cache_filename);
4677           return(MagickFalse);
4678         }
4679       break;
4680     }
4681     default:
4682       break;
4683   }
4684   if ((cache_info->debug != MagickFalse) &&
4685       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4686     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4687       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4688       nexus_info->region.width,(double) nexus_info->region.height,(double)
4689       nexus_info->region.x,(double) nexus_info->region.y);
4690   return(MagickTrue);
4691 }
4692 \f
4693 /*
4694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4695 %                                                                             %
4696 %                                                                             %
4697 %                                                                             %
4698 +   R e a d P i x e l C a c h e P i x e l s                                   %
4699 %                                                                             %
4700 %                                                                             %
4701 %                                                                             %
4702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703 %
4704 %  ReadPixelCachePixels() reads pixels from the specified region of the pixel
4705 %  cache.
4706 %
4707 %  The format of the ReadPixelCachePixels() method is:
4708 %
4709 %      MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4710 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4711 %
4712 %  A description of each parameter follows:
4713 %
4714 %    o cache_info: the pixel cache.
4715 %
4716 %    o nexus_info: the cache nexus to read the pixels.
4717 %
4718 %    o exception: return any errors or warnings in this structure.
4719 %
4720 */
4721 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4722   NexusInfo *nexus_info,ExceptionInfo *exception)
4723 {
4724   MagickOffsetType
4725     count,
4726     offset;
4727
4728   MagickSizeType
4729     extent,
4730     length;
4731
4732   register Quantum
4733     *restrict q;
4734
4735   register ssize_t
4736     y;
4737
4738   size_t
4739     rows;
4740
4741   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4742     return(MagickTrue);
4743   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4744     nexus_info->region.x;
4745   length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4746     sizeof(Quantum);
4747   rows=nexus_info->region.height;
4748   extent=length*rows;
4749   q=nexus_info->pixels;
4750   switch (cache_info->type)
4751   {
4752     case MemoryCache:
4753     case MapCache:
4754     {
4755       register Quantum
4756         *restrict p;
4757
4758       /*
4759         Read pixels from memory.
4760       */
4761       if ((cache_info->columns == nexus_info->region.width) &&
4762           (extent == (MagickSizeType) ((size_t) extent)))
4763         {
4764           length=extent;
4765           rows=1UL;
4766         }
4767       p=cache_info->pixels+offset*cache_info->number_channels;
4768       for (y=0; y < (ssize_t) rows; y++)
4769       {
4770         (void) memcpy(q,p,(size_t) length);
4771         p+=cache_info->number_channels*cache_info->columns;
4772         q+=cache_info->number_channels*nexus_info->region.width;
4773       }
4774       break;
4775     }
4776     case DiskCache:
4777     {
4778       /*
4779         Read pixels from disk.
4780       */
4781       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4782         {
4783           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4784             cache_info->cache_filename);
4785           return(MagickFalse);
4786         }
4787       if ((cache_info->columns == nexus_info->region.width) &&
4788           (extent <= MagickMaxBufferExtent))
4789         {
4790           length=extent;
4791           rows=1UL;
4792         }
4793       for (y=0; y < (ssize_t) rows; y++)
4794       {
4795         count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4796           cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4797         if ((MagickSizeType) count != length)
4798           break;
4799         offset+=cache_info->columns;
4800         q+=cache_info->number_channels*nexus_info->region.width;
4801       }
4802       if (y < (ssize_t) rows)
4803         {
4804           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4805             cache_info->cache_filename);
4806           return(MagickFalse);
4807         }
4808       break;
4809     }
4810     default:
4811       break;
4812   }
4813   if ((cache_info->debug != MagickFalse) &&
4814       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4815     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4816       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4817       nexus_info->region.width,(double) nexus_info->region.height,(double)
4818       nexus_info->region.x,(double) nexus_info->region.y);
4819   return(MagickTrue);
4820 }
4821 \f
4822 /*
4823 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4824 %                                                                             %
4825 %                                                                             %
4826 %                                                                             %
4827 +   R e f e r e n c e P i x e l C a c h e                                     %
4828 %                                                                             %
4829 %                                                                             %
4830 %                                                                             %
4831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4832 %
4833 %  ReferencePixelCache() increments the reference count associated with the
4834 %  pixel cache returning a pointer to the cache.
4835 %
4836 %  The format of the ReferencePixelCache method is:
4837 %
4838 %      Cache ReferencePixelCache(Cache cache_info)
4839 %
4840 %  A description of each parameter follows:
4841 %
4842 %    o cache_info: the pixel cache.
4843 %
4844 */
4845 MagickPrivate Cache ReferencePixelCache(Cache cache)
4846 {
4847   CacheInfo
4848     *cache_info;
4849
4850   assert(cache != (Cache *) NULL);
4851   cache_info=(CacheInfo *) cache;
4852   assert(cache_info->signature == MagickSignature);
4853   LockSemaphoreInfo(cache_info->semaphore);
4854   cache_info->reference_count++;
4855   UnlockSemaphoreInfo(cache_info->semaphore);
4856   return(cache_info);
4857 }
4858 \f
4859 /*
4860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4861 %                                                                             %
4862 %                                                                             %
4863 %                                                                             %
4864 +   S e t P i x e l C a c h e M e t h o d s                                   %
4865 %                                                                             %
4866 %                                                                             %
4867 %                                                                             %
4868 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4869 %
4870 %  SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4871 %
4872 %  The format of the SetPixelCacheMethods() method is:
4873 %
4874 %      SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4875 %
4876 %  A description of each parameter follows:
4877 %
4878 %    o cache: the pixel cache.
4879 %
4880 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
4881 %
4882 */
4883 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4884 {
4885   CacheInfo
4886     *cache_info;
4887
4888   GetOneAuthenticPixelFromHandler
4889     get_one_authentic_pixel_from_handler;
4890
4891   GetOneVirtualPixelFromHandler
4892     get_one_virtual_pixel_from_handler;
4893
4894   /*
4895     Set cache pixel methods.
4896   */
4897   assert(cache != (Cache) NULL);
4898   assert(cache_methods != (CacheMethods *) NULL);
4899   cache_info=(CacheInfo *) cache;
4900   assert(cache_info->signature == MagickSignature);
4901   if (cache_info->debug != MagickFalse)
4902     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4903       cache_info->filename);
4904   if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4905     cache_info->methods.get_virtual_pixel_handler=
4906       cache_methods->get_virtual_pixel_handler;
4907   if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4908     cache_info->methods.destroy_pixel_handler=
4909       cache_methods->destroy_pixel_handler;
4910   if (cache_methods->get_virtual_metacontent_from_handler !=
4911       (GetVirtualMetacontentFromHandler) NULL)
4912     cache_info->methods.get_virtual_metacontent_from_handler=
4913       cache_methods->get_virtual_metacontent_from_handler;
4914   if (cache_methods->get_authentic_pixels_handler !=
4915       (GetAuthenticPixelsHandler) NULL)
4916     cache_info->methods.get_authentic_pixels_handler=
4917       cache_methods->get_authentic_pixels_handler;
4918   if (cache_methods->queue_authentic_pixels_handler !=
4919       (QueueAuthenticPixelsHandler) NULL)
4920     cache_info->methods.queue_authentic_pixels_handler=
4921       cache_methods->queue_authentic_pixels_handler;
4922   if (cache_methods->sync_authentic_pixels_handler !=
4923       (SyncAuthenticPixelsHandler) NULL)
4924     cache_info->methods.sync_authentic_pixels_handler=
4925       cache_methods->sync_authentic_pixels_handler;
4926   if (cache_methods->get_authentic_pixels_from_handler !=
4927       (GetAuthenticPixelsFromHandler) NULL)
4928     cache_info->methods.get_authentic_pixels_from_handler=
4929       cache_methods->get_authentic_pixels_from_handler;
4930   if (cache_methods->get_authentic_metacontent_from_handler !=
4931       (GetAuthenticMetacontentFromHandler) NULL)
4932     cache_info->methods.get_authentic_metacontent_from_handler=
4933       cache_methods->get_authentic_metacontent_from_handler;
4934   get_one_virtual_pixel_from_handler=
4935     cache_info->methods.get_one_virtual_pixel_from_handler;
4936   if (get_one_virtual_pixel_from_handler !=
4937       (GetOneVirtualPixelFromHandler) NULL)
4938     cache_info->methods.get_one_virtual_pixel_from_handler=
4939       cache_methods->get_one_virtual_pixel_from_handler;
4940   get_one_authentic_pixel_from_handler=
4941     cache_methods->get_one_authentic_pixel_from_handler;
4942   if (get_one_authentic_pixel_from_handler !=
4943       (GetOneAuthenticPixelFromHandler) NULL)
4944     cache_info->methods.get_one_authentic_pixel_from_handler=
4945       cache_methods->get_one_authentic_pixel_from_handler;
4946 }
4947 \f
4948 /*
4949 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4950 %                                                                             %
4951 %                                                                             %
4952 %                                                                             %
4953 +   S e t P i x e l C a c h e N e x u s P i x e l s                           %
4954 %                                                                             %
4955 %                                                                             %
4956 %                                                                             %
4957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4958 %
4959 %  SetPixelCacheNexusPixels() defines the region of the cache for the
4960 %  specified cache nexus.
4961 %
4962 %  The format of the SetPixelCacheNexusPixels() method is:
4963 %
4964 %      Quantum SetPixelCacheNexusPixels(const Image *image,
4965 %        const RectangleInfo *region,NexusInfo *nexus_info,
4966 %        ExceptionInfo *exception)
4967 %
4968 %  A description of each parameter follows:
4969 %
4970 %    o image: the image.
4971 %
4972 %    o region: A pointer to the RectangleInfo structure that defines the
4973 %      region of this particular cache nexus.
4974 %
4975 %    o nexus_info: the cache nexus to set.
4976 %
4977 %    o exception: return any errors or warnings in this structure.
4978 %
4979 */
4980
4981 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4982   NexusInfo *nexus_info,ExceptionInfo *exception)
4983 {
4984   if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4985     return(MagickFalse);
4986   nexus_info->mapped=MagickFalse;
4987   nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
4988     nexus_info->length);
4989   if (nexus_info->cache == (Quantum *) NULL)
4990     {
4991       nexus_info->mapped=MagickTrue;
4992       nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4993         nexus_info->length);
4994     }
4995   if (nexus_info->cache == (Quantum *) NULL)
4996     {
4997       (void) ThrowMagickException(exception,GetMagickModule(),
4998         ResourceLimitError,"MemoryAllocationFailed","`%s'",
4999         cache_info->filename);
5000       return(MagickFalse);
5001     }
5002   return(MagickTrue);
5003 }
5004
5005 static Quantum *SetPixelCacheNexusPixels(const Image *image,
5006   const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5007 {
5008   CacheInfo
5009     *cache_info;
5010
5011   MagickBooleanType
5012     status;
5013
5014   MagickSizeType
5015     length,
5016     number_pixels;
5017
5018   cache_info=(CacheInfo *) image->cache;
5019   assert(cache_info->signature == MagickSignature);
5020   if (cache_info->type == UndefinedCache)
5021     return((Quantum *) NULL);
5022   nexus_info->region=(*region);
5023   if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5024       (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5025     {
5026       ssize_t
5027         x,
5028         y;
5029
5030       x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5031       y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5032       if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5033            (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5034           ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5035            ((nexus_info->region.width == cache_info->columns) ||
5036             ((nexus_info->region.width % cache_info->columns) == 0)))))
5037         {
5038           MagickOffsetType
5039             offset;
5040
5041           /*
5042             Pixels are accessed directly from memory.
5043           */
5044           offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5045             nexus_info->region.x;
5046           nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5047             offset;
5048           nexus_info->metacontent=(void *) NULL;
5049           if (cache_info->metacontent_extent != 0)
5050             nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5051               offset*cache_info->metacontent_extent;
5052           return(nexus_info->pixels);
5053         }
5054     }
5055   /*
5056     Pixels are stored in a cache region until they are synced to the cache.
5057   */
5058   number_pixels=(MagickSizeType) nexus_info->region.width*
5059     nexus_info->region.height;
5060   length=number_pixels*cache_info->number_channels*sizeof(Quantum);
5061   if (cache_info->metacontent_extent != 0)
5062     length+=number_pixels*cache_info->metacontent_extent;
5063   if (nexus_info->cache == (Quantum *) NULL)
5064     {
5065       nexus_info->length=length;
5066       status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5067       if (status == MagickFalse)
5068         {
5069           nexus_info->length=0;
5070           return((Quantum *) NULL);
5071         }
5072     }
5073   else
5074     if (nexus_info->length != length)
5075       {
5076         RelinquishCacheNexusPixels(nexus_info);
5077         nexus_info->length=length;
5078         status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5079         if (status == MagickFalse)
5080           {
5081             nexus_info->length=0;
5082             return((Quantum *) NULL);
5083           }
5084       }
5085   nexus_info->pixels=nexus_info->cache;
5086   nexus_info->metacontent=(void *) NULL;
5087   if (cache_info->metacontent_extent != 0)
5088     nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
5089       cache_info->number_channels);
5090   return(nexus_info->pixels);
5091 }
5092 \f
5093 /*
5094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5095 %                                                                             %
5096 %                                                                             %
5097 %                                                                             %
5098 %   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                       %
5099 %                                                                             %
5100 %                                                                             %
5101 %                                                                             %
5102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5103 %
5104 %  SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5105 %  pixel cache and returns the previous setting.  A virtual pixel is any pixel
5106 %  access that is outside the boundaries of the image cache.
5107 %
5108 %  The format of the SetPixelCacheVirtualMethod() method is:
5109 %
5110 %      VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5111 %        const VirtualPixelMethod virtual_pixel_method)
5112 %
5113 %  A description of each parameter follows:
5114 %
5115 %    o image: the image.
5116 %
5117 %    o virtual_pixel_method: choose the type of virtual pixel.
5118 %
5119 */
5120 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5121   const VirtualPixelMethod virtual_pixel_method)
5122 {
5123   CacheInfo
5124     *cache_info;
5125
5126   VirtualPixelMethod
5127     method;
5128
5129   assert(image != (Image *) NULL);
5130   assert(image->signature == MagickSignature);
5131   if (image->debug != MagickFalse)
5132     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5133   assert(image->cache != (Cache) NULL);
5134   cache_info=(CacheInfo *) image->cache;
5135   assert(cache_info->signature == MagickSignature);
5136   method=cache_info->virtual_pixel_method;
5137   cache_info->virtual_pixel_method=virtual_pixel_method;
5138   return(method);
5139 }
5140 \f
5141 /*
5142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5143 %                                                                             %
5144 %                                                                             %
5145 %                                                                             %
5146 +   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                   %
5147 %                                                                             %
5148 %                                                                             %
5149 %                                                                             %
5150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5151 %
5152 %  SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5153 %  in-memory or disk cache.  The method returns MagickTrue if the pixel region
5154 %  is synced, otherwise MagickFalse.
5155 %
5156 %  The format of the SyncAuthenticPixelCacheNexus() method is:
5157 %
5158 %      MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5159 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5160 %
5161 %  A description of each parameter follows:
5162 %
5163 %    o image: the image.
5164 %
5165 %    o nexus_info: the cache nexus to sync.
5166 %
5167 %    o exception: return any errors or warnings in this structure.
5168 %
5169 */
5170 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5171   NexusInfo *nexus_info,ExceptionInfo *exception)
5172 {
5173   CacheInfo
5174     *cache_info;
5175
5176   MagickBooleanType
5177     status;
5178
5179   /*
5180     Transfer pixels to the cache.
5181   */
5182   assert(image != (Image *) NULL);
5183   assert(image->signature == MagickSignature);
5184   if (image->cache == (Cache) NULL)
5185     ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5186   cache_info=(CacheInfo *) image->cache;
5187   assert(cache_info->signature == MagickSignature);
5188   if (cache_info->type == UndefinedCache)
5189     return(MagickFalse);
5190   if ((image->clip_mask != (Image *) NULL) &&
5191       (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5192     return(MagickFalse);
5193   if ((image->mask != (Image *) NULL) &&
5194       (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5195     return(MagickFalse);
5196   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5197     return(MagickTrue);
5198   assert(cache_info->signature == MagickSignature);
5199   status=WritePixelCachePixels(cache_info,nexus_info,exception);
5200   if ((cache_info->metacontent_extent != 0) &&
5201       (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5202     return(MagickFalse);
5203   return(status);
5204 }
5205 \f
5206 /*
5207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5208 %                                                                             %
5209 %                                                                             %
5210 %                                                                             %
5211 +   S y n c A u t h e n t i c P i x e l C a c h e                             %
5212 %                                                                             %
5213 %                                                                             %
5214 %                                                                             %
5215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5216 %
5217 %  SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5218 %  or disk cache.  The method returns MagickTrue if the pixel region is synced,
5219 %  otherwise MagickFalse.
5220 %
5221 %  The format of the SyncAuthenticPixelsCache() method is:
5222 %
5223 %      MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5224 %        ExceptionInfo *exception)
5225 %
5226 %  A description of each parameter follows:
5227 %
5228 %    o image: the image.
5229 %
5230 %    o exception: return any errors or warnings in this structure.
5231 %
5232 */
5233 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5234   ExceptionInfo *exception)
5235 {
5236   CacheInfo
5237     *cache_info;
5238
5239   const int
5240     id = GetOpenMPThreadId();
5241
5242   MagickBooleanType
5243     status;
5244
5245   assert(image != (Image *) NULL);
5246   assert(image->signature == MagickSignature);
5247   assert(image->cache != (Cache) NULL);
5248   cache_info=(CacheInfo *) image->cache;
5249   assert(cache_info->signature == MagickSignature);
5250   assert(id < (int) cache_info->number_threads);
5251   status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5252     exception);
5253   return(status);
5254 }
5255 \f
5256 /*
5257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5258 %                                                                             %
5259 %                                                                             %
5260 %                                                                             %
5261 %   S y n c A u t h e n t i c P i x e l s                                     %
5262 %                                                                             %
5263 %                                                                             %
5264 %                                                                             %
5265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5266 %
5267 %  SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5268 %  The method returns MagickTrue if the pixel region is flushed, otherwise
5269 %  MagickFalse.
5270 %
5271 %  The format of the SyncAuthenticPixels() method is:
5272 %
5273 %      MagickBooleanType SyncAuthenticPixels(Image *image,
5274 %        ExceptionInfo *exception)
5275 %
5276 %  A description of each parameter follows:
5277 %
5278 %    o image: the image.
5279 %
5280 %    o exception: return any errors or warnings in this structure.
5281 %
5282 */
5283 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5284   ExceptionInfo *exception)
5285 {
5286   CacheInfo
5287     *cache_info;
5288
5289   const int
5290     id = GetOpenMPThreadId();
5291
5292   MagickBooleanType
5293     status;
5294
5295   assert(image != (Image *) NULL);
5296   assert(image->signature == MagickSignature);
5297   assert(image->cache != (Cache) NULL);
5298   cache_info=(CacheInfo *) image->cache;
5299   assert(cache_info->signature == MagickSignature);
5300   if (cache_info->methods.sync_authentic_pixels_handler !=
5301        (SyncAuthenticPixelsHandler) NULL)
5302     {
5303       status=cache_info->methods.sync_authentic_pixels_handler(image,
5304         exception);
5305       return(status);
5306     }
5307   assert(id < (int) cache_info->number_threads);
5308   status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5309     exception);
5310   return(status);
5311 }
5312 \f
5313 /*
5314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5315 %                                                                             %
5316 %                                                                             %
5317 %                                                                             %
5318 +   S y n c I m a g e P i x e l C a c h e                                     %
5319 %                                                                             %
5320 %                                                                             %
5321 %                                                                             %
5322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5323 %
5324 %  SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5325 %  The method returns MagickTrue if the pixel region is flushed, otherwise
5326 %  MagickFalse.
5327 %
5328 %  The format of the SyncImagePixelCache() method is:
5329 %
5330 %      MagickBooleanType SyncImagePixelCache(Image *image,
5331 %        ExceptionInfo *exception)
5332 %
5333 %  A description of each parameter follows:
5334 %
5335 %    o image: the image.
5336 %
5337 %    o exception: return any errors or warnings in this structure.
5338 %
5339 */
5340 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5341   ExceptionInfo *exception)
5342 {
5343   CacheInfo
5344     *cache_info;
5345
5346   assert(image != (Image *) NULL);
5347   assert(exception != (ExceptionInfo *) NULL);
5348   cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5349   return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5350 }
5351 \f
5352 /*
5353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5354 %                                                                             %
5355 %                                                                             %
5356 %                                                                             %
5357 +   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                       %
5358 %                                                                             %
5359 %                                                                             %
5360 %                                                                             %
5361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5362 %
5363 %  WritePixelCacheMetacontent() writes the meta-content to the specified region
5364 %  of the pixel cache.
5365 %
5366 %  The format of the WritePixelCacheMetacontent() method is:
5367 %
5368 %      MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5369 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5370 %
5371 %  A description of each parameter follows:
5372 %
5373 %    o cache_info: the pixel cache.
5374 %
5375 %    o nexus_info: the cache nexus to write the meta-content.
5376 %
5377 %    o exception: return any errors or warnings in this structure.
5378 %
5379 */
5380 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5381   NexusInfo *nexus_info,ExceptionInfo *exception)
5382 {
5383   MagickOffsetType
5384     count,
5385     offset;
5386
5387   MagickSizeType
5388     extent,
5389     length;
5390
5391   register const unsigned char
5392     *restrict p;
5393
5394   register ssize_t
5395     y;
5396
5397   size_t
5398     rows;
5399
5400   if (cache_info->metacontent_extent == 0)
5401     return(MagickFalse);
5402   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5403     return(MagickTrue);
5404   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5405     nexus_info->region.x;
5406   length=(MagickSizeType) nexus_info->region.width*
5407     cache_info->metacontent_extent;
5408   rows=nexus_info->region.height;
5409   extent=(MagickSizeType) length*rows;
5410   p=(unsigned char *) nexus_info->metacontent;
5411   switch (cache_info->type)
5412   {
5413     case MemoryCache:
5414     case MapCache:
5415     {
5416       register unsigned char
5417         *restrict q;
5418
5419       /*
5420         Write associated pixels to memory.
5421       */
5422       if ((cache_info->columns == nexus_info->region.width) &&
5423           (extent == (MagickSizeType) ((size_t) extent)))
5424         {
5425           length=extent;
5426           rows=1UL;
5427         }
5428       q=(unsigned char *) cache_info->metacontent+offset*
5429         cache_info->metacontent_extent;
5430       for (y=0; y < (ssize_t) rows; y++)
5431       {
5432         (void) memcpy(q,p,(size_t) length);
5433         p+=nexus_info->region.width*cache_info->metacontent_extent;
5434         q+=cache_info->columns*cache_info->metacontent_extent;
5435       }
5436       break;
5437     }
5438     case DiskCache:
5439     {
5440       /*
5441         Write associated pixels to disk.
5442       */
5443       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5444         {
5445           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5446             cache_info->cache_filename);
5447           return(MagickFalse);
5448         }
5449       if ((cache_info->columns == nexus_info->region.width) &&
5450           (extent <= MagickMaxBufferExtent))
5451         {
5452           length=extent;
5453           rows=1UL;
5454         }
5455       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5456       for (y=0; y < (ssize_t) rows; y++)
5457       {
5458         count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5459           cache_info->number_channels*sizeof(Quantum)+offset*
5460           cache_info->metacontent_extent,length,(const unsigned char *) p);
5461         if ((MagickSizeType) count != length)
5462           break;
5463         p+=nexus_info->region.width*cache_info->metacontent_extent;
5464         offset+=cache_info->columns;
5465       }
5466       if (y < (ssize_t) rows)
5467         {
5468           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5469             cache_info->cache_filename);
5470           return(MagickFalse);
5471         }
5472       break;
5473     }
5474     default:
5475       break;
5476   }
5477   if ((cache_info->debug != MagickFalse) &&
5478       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5479     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5480       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5481       nexus_info->region.width,(double) nexus_info->region.height,(double)
5482       nexus_info->region.x,(double) nexus_info->region.y);
5483   return(MagickTrue);
5484 }
5485 \f
5486 /*
5487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5488 %                                                                             %
5489 %                                                                             %
5490 %                                                                             %
5491 +   W r i t e C a c h e P i x e l s                                           %
5492 %                                                                             %
5493 %                                                                             %
5494 %                                                                             %
5495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5496 %
5497 %  WritePixelCachePixels() writes image pixels to the specified region of the
5498 %  pixel cache.
5499 %
5500 %  The format of the WritePixelCachePixels() method is:
5501 %
5502 %      MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5503 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5504 %
5505 %  A description of each parameter follows:
5506 %
5507 %    o cache_info: the pixel cache.
5508 %
5509 %    o nexus_info: the cache nexus to write the pixels.
5510 %
5511 %    o exception: return any errors or warnings in this structure.
5512 %
5513 */
5514 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5515   NexusInfo *nexus_info,ExceptionInfo *exception)
5516 {
5517   MagickOffsetType
5518     count,
5519     offset;
5520
5521   MagickSizeType
5522     extent,
5523     length;
5524
5525   register const Quantum
5526     *restrict p;
5527
5528   register ssize_t
5529     y;
5530
5531   size_t
5532     rows;
5533
5534   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5535     return(MagickTrue);
5536   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5537     nexus_info->region.x;
5538   length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5539     sizeof(Quantum);
5540   rows=nexus_info->region.height;
5541   extent=length*rows;
5542   p=nexus_info->pixels;
5543   switch (cache_info->type)
5544   {
5545     case MemoryCache:
5546     case MapCache:
5547     {
5548       register Quantum
5549         *restrict q;
5550
5551       /*
5552         Write pixels to memory.
5553       */
5554       if ((cache_info->columns == nexus_info->region.width) &&
5555           (extent == (MagickSizeType) ((size_t) extent)))
5556         {
5557           length=extent;
5558           rows=1UL;
5559         }
5560       q=cache_info->pixels+offset*cache_info->number_channels;
5561       for (y=0; y < (ssize_t) rows; y++)
5562       {
5563         (void) memcpy(q,p,(size_t) length);
5564         p+=nexus_info->region.width*cache_info->number_channels;
5565         q+=cache_info->columns*cache_info->number_channels;
5566       }
5567       break;
5568     }
5569     case DiskCache:
5570     {
5571       /*
5572         Write pixels to disk.
5573       */
5574       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5575         {
5576           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5577             cache_info->cache_filename);
5578           return(MagickFalse);
5579         }
5580       if ((cache_info->columns == nexus_info->region.width) &&
5581           (extent <= MagickMaxBufferExtent))
5582         {
5583           length=extent;
5584           rows=1UL;
5585         }
5586       for (y=0; y < (ssize_t) rows; y++)
5587       {
5588         count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5589           cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5590           p);
5591         if ((MagickSizeType) count != length)
5592           break;
5593         p+=nexus_info->region.width*cache_info->number_channels;
5594         offset+=cache_info->columns;
5595       }
5596       if (y < (ssize_t) rows)
5597         {
5598           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5599             cache_info->cache_filename);
5600           return(MagickFalse);
5601         }
5602       break;
5603     }
5604     default:
5605       break;
5606   }
5607   if ((cache_info->debug != MagickFalse) &&
5608       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5609     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5610       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5611       nexus_info->region.width,(double) nexus_info->region.height,(double)
5612       nexus_info->region.x,(double) nexus_info->region.y);
5613   return(MagickTrue);
5614 }