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