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