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