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