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