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