]> 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(const Cache cache,
2938   NexusInfo *nexus_info)
2939 {
2940   CacheInfo
2941     *cache_info;
2942
2943   assert(cache != (Cache) NULL);
2944   cache_info=(CacheInfo *) cache;
2945   assert(cache_info->signature == MagickSignature);
2946   if (cache_info->storage_class == UndefinedClass)
2947     return((void *) NULL);
2948   return(nexus_info->metacontent);
2949 }
2950 \f
2951 /*
2952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2953 %                                                                             %
2954 %                                                                             %
2955 %                                                                             %
2956 %   G e t V i r t u a l M e t a c o n t e n t                                 %
2957 %                                                                             %
2958 %                                                                             %
2959 %                                                                             %
2960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2961 %
2962 %  GetVirtualMetacontent() returns the virtual metacontent corresponding with
2963 %  the last call to QueueAuthenticPixels() or GetVirtualPixels().  NULL is
2964 %  returned if the meta-content are not available.
2965 %
2966 %  The format of the GetVirtualMetacontent() method is:
2967 %
2968 %      const void *GetVirtualMetacontent(const Image *image)
2969 %
2970 %  A description of each parameter follows:
2971 %
2972 %    o image: the image.
2973 %
2974 */
2975 MagickExport const void *GetVirtualMetacontent(const Image *image)
2976 {
2977   CacheInfo
2978     *cache_info;
2979
2980   const int
2981     id = GetOpenMPThreadId();
2982
2983   const void
2984     *metacontent;
2985
2986   assert(image != (const Image *) NULL);
2987   assert(image->signature == MagickSignature);
2988   assert(image->cache != (Cache) NULL);
2989   cache_info=(CacheInfo *) image->cache;
2990   assert(cache_info->signature == MagickSignature);
2991   if (cache_info->methods.get_virtual_metacontent_from_handler !=
2992        (GetVirtualMetacontentFromHandler) NULL)
2993     {
2994       metacontent=cache_info->methods.
2995         get_virtual_metacontent_from_handler(image);
2996       return(metacontent);
2997     }
2998   assert(id < (int) cache_info->number_threads);
2999   metacontent=GetVirtualMetacontentFromNexus(cache_info,
3000     cache_info->nexus_info[id]);
3001   return(metacontent);
3002 }
3003 \f
3004 /*
3005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3006 %                                                                             %
3007 %                                                                             %
3008 %                                                                             %
3009 +   G e t V i r t u a l P i x e l s F r o m N e x u s                         %
3010 %                                                                             %
3011 %                                                                             %
3012 %                                                                             %
3013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3014 %
3015 %  GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3016 %  pixel cache as defined by the geometry parameters.   A pointer to the pixels
3017 %  is returned if the pixels are transferred, otherwise a NULL is returned.
3018 %
3019 %  The format of the GetVirtualPixelsFromNexus() method is:
3020 %
3021 %      Quantum *GetVirtualPixelsFromNexus(const Image *image,
3022 %        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3023 %        const size_t columns,const size_t rows,NexusInfo *nexus_info,
3024 %        ExceptionInfo *exception)
3025 %
3026 %  A description of each parameter follows:
3027 %
3028 %    o image: the image.
3029 %
3030 %    o virtual_pixel_method: the virtual pixel method.
3031 %
3032 %    o x,y,columns,rows:  These values define the perimeter of a region of
3033 %      pixels.
3034 %
3035 %    o nexus_info: the cache nexus to acquire.
3036 %
3037 %    o exception: return any errors or warnings in this structure.
3038 %
3039 */
3040
3041 static ssize_t
3042   DitherMatrix[64] =
3043   {
3044      0,  48,  12,  60,   3,  51,  15,  63,
3045     32,  16,  44,  28,  35,  19,  47,  31,
3046      8,  56,   4,  52,  11,  59,   7,  55,
3047     40,  24,  36,  20,  43,  27,  39,  23,
3048      2,  50,  14,  62,   1,  49,  13,  61,
3049     34,  18,  46,  30,  33,  17,  45,  29,
3050     10,  58,   6,  54,   9,  57,   5,  53,
3051     42,  26,  38,  22,  41,  25,  37,  21
3052   };
3053
3054 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3055 {
3056   ssize_t
3057     index;
3058
3059   index=x+DitherMatrix[x & 0x07]-32L;
3060   if (index < 0L)
3061     return(0L);
3062   if (index >= (ssize_t) columns)
3063     return((ssize_t) columns-1L);
3064   return(index);
3065 }
3066
3067 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3068 {
3069   ssize_t
3070     index;
3071
3072   index=y+DitherMatrix[y & 0x07]-32L;
3073   if (index < 0L)
3074     return(0L);
3075   if (index >= (ssize_t) rows)
3076     return((ssize_t) rows-1L);
3077   return(index);
3078 }
3079
3080 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3081 {
3082   if (x < 0L)
3083     return(0L);
3084   if (x >= (ssize_t) columns)
3085     return((ssize_t) (columns-1));
3086   return(x);
3087 }
3088
3089 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3090 {
3091   if (y < 0L)
3092     return(0L);
3093   if (y >= (ssize_t) rows)
3094     return((ssize_t) (rows-1));
3095   return(y);
3096 }
3097
3098 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3099 {
3100   return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3101 }
3102
3103 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3104 {
3105   return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3106 }
3107
3108 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3109   const size_t extent)
3110 {
3111   MagickModulo
3112     modulo;
3113
3114   /*
3115     Compute the remainder of dividing offset by extent.  It returns not only
3116     the quotient (tile the offset falls in) but also the positive remainer
3117     within that tile such that 0 <= remainder < extent.  This method is
3118     essentially a ldiv() using a floored modulo division rather than the
3119     normal default truncated modulo division.
3120   */
3121   modulo.quotient=offset/(ssize_t) extent;
3122   if (offset < 0L)
3123     modulo.quotient--;
3124   modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3125   return(modulo);
3126 }
3127
3128 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       if (cache_info->metacontent_extent != 0)
3251         {
3252           /*
3253             Acquire a metacontent buffer.
3254           */
3255           virtual_metacontent=(void *) AcquireAlignedMemory(1,
3256             cache_info->metacontent_extent);
3257           if (virtual_metacontent == (void *) NULL)
3258             {
3259               virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3260               (void) ThrowMagickException(exception,GetMagickModule(),
3261                 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3262               return((const Quantum *) NULL);
3263             }
3264           (void) ResetMagickMemory(virtual_metacontent,0,
3265             cache_info->metacontent_extent);
3266         }
3267       switch (virtual_pixel_method)
3268       {
3269         case BlackVirtualPixelMethod:
3270         {
3271           for (i=0; i < 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           if (image->colorspace == CMYKColorspace)
3304             SetPixelBlack(image,image->background_color.black,virtual_pixel);
3305           SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3306           break;
3307         }
3308       }
3309       break;
3310     }
3311     default:
3312       break;
3313   }
3314   for (v=0; v < (ssize_t) rows; v++)
3315   {
3316     for (u=0; u < (ssize_t) columns; u+=length)
3317     {
3318       length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3319       if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3320           (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3321           (length == 0))
3322         {
3323           MagickModulo
3324             x_modulo,
3325             y_modulo;
3326
3327           /*
3328             Transfer a single pixel.
3329           */
3330           length=(MagickSizeType) 1;
3331           switch (virtual_pixel_method)
3332           {
3333             default:
3334             {
3335               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3336                 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3337                 1UL,1UL,*virtual_nexus,exception);
3338               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3339               break;
3340             }
3341             case RandomVirtualPixelMethod:
3342             {
3343               if (cache_info->random_info == (RandomInfo *) NULL)
3344                 cache_info->random_info=AcquireRandomInfo();
3345               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3346                 RandomX(cache_info->random_info,cache_info->columns),
3347                 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3348                 *virtual_nexus,exception);
3349               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3350               break;
3351             }
3352             case DitherVirtualPixelMethod:
3353             {
3354               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3355                 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3356                 1UL,1UL,*virtual_nexus,exception);
3357               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3358               break;
3359             }
3360             case TileVirtualPixelMethod:
3361             {
3362               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3363               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3364               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3365                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3366                 exception);
3367               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3368               break;
3369             }
3370             case MirrorVirtualPixelMethod:
3371             {
3372               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3373               if ((x_modulo.quotient & 0x01) == 1L)
3374                 x_modulo.remainder=(ssize_t) cache_info->columns-
3375                   x_modulo.remainder-1L;
3376               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3377               if ((y_modulo.quotient & 0x01) == 1L)
3378                 y_modulo.remainder=(ssize_t) cache_info->rows-
3379                   y_modulo.remainder-1L;
3380               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3381                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3382                 exception);
3383               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3384               break;
3385             }
3386             case HorizontalTileEdgeVirtualPixelMethod:
3387             {
3388               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3389               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3390                 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3391                 *virtual_nexus,exception);
3392               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3393               break;
3394             }
3395             case VerticalTileEdgeVirtualPixelMethod:
3396             {
3397               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3398               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3399                 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3400                 *virtual_nexus,exception);
3401               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3402               break;
3403             }
3404             case BackgroundVirtualPixelMethod:
3405             case BlackVirtualPixelMethod:
3406             case GrayVirtualPixelMethod:
3407             case TransparentVirtualPixelMethod:
3408             case MaskVirtualPixelMethod:
3409             case WhiteVirtualPixelMethod:
3410             {
3411               p=virtual_pixel;
3412               r=virtual_metacontent;
3413               break;
3414             }
3415             case EdgeVirtualPixelMethod:
3416             case CheckerTileVirtualPixelMethod:
3417             {
3418               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3419               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3420               if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3421                 {
3422                   p=virtual_pixel;
3423                   r=virtual_metacontent;
3424                   break;
3425                 }
3426               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3427                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3428                 exception);
3429               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3430               break;
3431             }
3432             case HorizontalTileVirtualPixelMethod:
3433             {
3434               if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3435                 {
3436                   p=virtual_pixel;
3437                   r=virtual_metacontent;
3438                   break;
3439                 }
3440               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3441               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3442               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3443                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3444                 exception);
3445               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3446               break;
3447             }
3448             case VerticalTileVirtualPixelMethod:
3449             {
3450               if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3451                 {
3452                   p=virtual_pixel;
3453                   r=virtual_metacontent;
3454                   break;
3455                 }
3456               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3457               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3458               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3459                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3460                 exception);
3461               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3462               break;
3463             }
3464           }
3465           if (p == (const Quantum *) NULL)
3466             break;
3467           (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3468             sizeof(*p));
3469           q+=cache_info->number_channels;
3470           if ((s != (void *) NULL) && (r != (const void *) NULL))
3471             {
3472               (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3473               s+=cache_info->metacontent_extent;
3474             }
3475           continue;
3476         }
3477       /*
3478         Transfer a run of pixels.
3479       */
3480       p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3481         length,1UL,*virtual_nexus,exception);
3482       if (p == (const Quantum *) NULL)
3483         break;
3484       r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3485       (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3486       q+=length*cache_info->number_channels;
3487       if ((r != (void *) NULL) && (s != (const void *) NULL))
3488         {
3489           (void) memcpy(s,r,(size_t) length);
3490           s+=length*cache_info->metacontent_extent;
3491         }
3492     }
3493   }
3494   /*
3495     Free resources.
3496   */
3497   if (virtual_metacontent != (void *) NULL)
3498     virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3499   virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3500   return(pixels);
3501 }
3502 \f
3503 /*
3504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3505 %                                                                             %
3506 %                                                                             %
3507 %                                                                             %
3508 +   G e t V i r t u a l P i x e l C a c h e                                   %
3509 %                                                                             %
3510 %                                                                             %
3511 %                                                                             %
3512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3513 %
3514 %  GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3515 %  cache as defined by the geometry parameters.   A pointer to the pixels
3516 %  is returned if the pixels are transferred, otherwise a NULL is returned.
3517 %
3518 %  The format of the GetVirtualPixelCache() method is:
3519 %
3520 %      const Quantum *GetVirtualPixelCache(const Image *image,
3521 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3522 %        const ssize_t y,const size_t columns,const size_t rows,
3523 %        ExceptionInfo *exception)
3524 %
3525 %  A description of each parameter follows:
3526 %
3527 %    o image: the image.
3528 %
3529 %    o virtual_pixel_method: the virtual pixel method.
3530 %
3531 %    o x,y,columns,rows:  These values define the perimeter of a region of
3532 %      pixels.
3533 %
3534 %    o exception: return any errors or warnings in this structure.
3535 %
3536 */
3537 static const Quantum *GetVirtualPixelCache(const Image *image,
3538   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3539   const size_t columns,const size_t rows,ExceptionInfo *exception)
3540 {
3541   CacheInfo
3542     *cache_info;
3543
3544   const int
3545     id = GetOpenMPThreadId();
3546
3547   const Quantum
3548     *pixels;
3549
3550   assert(image != (const Image *) NULL);
3551   assert(image->signature == MagickSignature);
3552   assert(image->cache != (Cache) NULL);
3553   cache_info=(CacheInfo *) image->cache;
3554   assert(cache_info->signature == MagickSignature);
3555   assert(id < (int) cache_info->number_threads);
3556   pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3557     cache_info->nexus_info[id],exception);
3558   return(pixels);
3559 }
3560 \f
3561 /*
3562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3563 %                                                                             %
3564 %                                                                             %
3565 %                                                                             %
3566 %   G e t V i r t u a l P i x e l Q u e u e                                   %
3567 %                                                                             %
3568 %                                                                             %
3569 %                                                                             %
3570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3571 %
3572 %  GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3573 %  with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3574 %
3575 %  The format of the GetVirtualPixelQueue() method is:
3576 %
3577 %      const Quantum *GetVirtualPixelQueue(const Image image)
3578 %
3579 %  A description of each parameter follows:
3580 %
3581 %    o image: the image.
3582 %
3583 */
3584 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3585 {
3586   CacheInfo
3587     *cache_info;
3588
3589   const int
3590     id = GetOpenMPThreadId();
3591
3592   assert(image != (const Image *) NULL);
3593   assert(image->signature == MagickSignature);
3594   assert(image->cache != (Cache) NULL);
3595   cache_info=(CacheInfo *) image->cache;
3596   assert(cache_info->signature == MagickSignature);
3597   if (cache_info->methods.get_virtual_pixels_handler !=
3598        (GetVirtualPixelsHandler) NULL)
3599     return(cache_info->methods.get_virtual_pixels_handler(image));
3600   assert(id < (int) cache_info->number_threads);
3601   return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3602 }
3603 \f
3604 /*
3605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3606 %                                                                             %
3607 %                                                                             %
3608 %                                                                             %
3609 %   G e t V i r t u a l P i x e l s                                           %
3610 %                                                                             %
3611 %                                                                             %
3612 %                                                                             %
3613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614 %
3615 %  GetVirtualPixels() returns an immutable pixel region. If the
3616 %  region is successfully accessed, a pointer to it is returned, otherwise
3617 %  NULL is returned.  The returned pointer may point to a temporary working
3618 %  copy of the pixels or it may point to the original pixels in memory.
3619 %  Performance is maximized if the selected region is part of one row, or one
3620 %  or more full rows, since there is opportunity to access the pixels in-place
3621 %  (without a copy) if the image is in memory, or in a memory-mapped file.  The
3622 %  returned pointer must *never* be deallocated by the user.
3623 %
3624 %  Pixels accessed via the returned pointer represent a simple array of type
3625 %  Quantum.  If the image type is CMYK or the storage class is PseudoClass,
3626 %  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3627 %  access the meta-content (of type void) corresponding to the the
3628 %  region.
3629 %
3630 %  If you plan to modify the pixels, use GetAuthenticPixels() instead.
3631 %
3632 %  Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3633 %  safe.  In a threaded environment, use GetCacheViewVirtualPixels() or
3634 %  GetCacheViewAuthenticPixels() instead.
3635 %
3636 %  The format of the GetVirtualPixels() method is:
3637 %
3638 %      const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3639 %        const ssize_t y,const size_t columns,const size_t rows,
3640 %        ExceptionInfo *exception)
3641 %
3642 %  A description of each parameter follows:
3643 %
3644 %    o image: the image.
3645 %
3646 %    o x,y,columns,rows:  These values define the perimeter of a region of
3647 %      pixels.
3648 %
3649 %    o exception: return any errors or warnings in this structure.
3650 %
3651 */
3652 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3653   const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3654   ExceptionInfo *exception)
3655 {
3656   CacheInfo
3657     *cache_info;
3658
3659   const int
3660     id = GetOpenMPThreadId();
3661
3662   const Quantum
3663     *pixels;
3664
3665   assert(image != (const Image *) NULL);
3666   assert(image->signature == MagickSignature);
3667   assert(image->cache != (Cache) NULL);
3668   cache_info=(CacheInfo *) image->cache;
3669   assert(cache_info->signature == MagickSignature);
3670   if (cache_info->methods.get_virtual_pixel_handler !=
3671        (GetVirtualPixelHandler) NULL)
3672     return(cache_info->methods.get_virtual_pixel_handler(image,
3673       GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3674   assert(id < (int) cache_info->number_threads);
3675   pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3676     columns,rows,cache_info->nexus_info[id],exception);
3677   return(pixels);
3678 }
3679 \f
3680 /*
3681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3682 %                                                                             %
3683 %                                                                             %
3684 %                                                                             %
3685 +   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                         %
3686 %                                                                             %
3687 %                                                                             %
3688 %                                                                             %
3689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3690 %
3691 %  GetVirtualPixelsCache() returns the pixels associated corresponding with the
3692 %  last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3693 %
3694 %  The format of the GetVirtualPixelsCache() method is:
3695 %
3696 %      Quantum *GetVirtualPixelsCache(const Image *image)
3697 %
3698 %  A description of each parameter follows:
3699 %
3700 %    o image: the image.
3701 %
3702 */
3703 static const Quantum *GetVirtualPixelsCache(const Image *image)
3704 {
3705   CacheInfo
3706     *cache_info;
3707
3708   const int
3709     id = GetOpenMPThreadId();
3710
3711   assert(image != (const Image *) NULL);
3712   assert(image->signature == MagickSignature);
3713   assert(image->cache != (Cache) NULL);
3714   cache_info=(CacheInfo *) image->cache;
3715   assert(cache_info->signature == MagickSignature);
3716   assert(id < (int) cache_info->number_threads);
3717   return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3718 }
3719 \f
3720 /*
3721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3722 %                                                                             %
3723 %                                                                             %
3724 %                                                                             %
3725 +   G e t V i r t u a l P i x e l s N e x u s                                 %
3726 %                                                                             %
3727 %                                                                             %
3728 %                                                                             %
3729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3730 %
3731 %  GetVirtualPixelsNexus() returns the pixels associated with the specified
3732 %  cache nexus.
3733 %
3734 %  The format of the GetVirtualPixelsNexus() method is:
3735 %
3736 %      const Quantum *GetVirtualPixelsNexus(const Cache cache,
3737 %        NexusInfo *nexus_info)
3738 %
3739 %  A description of each parameter follows:
3740 %
3741 %    o cache: the pixel cache.
3742 %
3743 %    o nexus_info: the cache nexus to return the colormap pixels.
3744 %
3745 */
3746 MagickExport const Quantum *GetVirtualPixelsNexus(const Cache cache,
3747   NexusInfo *nexus_info)
3748 {
3749   CacheInfo
3750     *cache_info;
3751
3752   assert(cache != (Cache) NULL);
3753   cache_info=(CacheInfo *) cache;
3754   assert(cache_info->signature == MagickSignature);
3755   if (cache_info->storage_class == UndefinedClass)
3756     return((Quantum *) NULL);
3757   return((const Quantum *) nexus_info->pixels);
3758 }
3759 \f
3760 /*
3761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3762 %                                                                             %
3763 %                                                                             %
3764 %                                                                             %
3765 +   M a s k P i x e l C a c h e N e x u s                                     %
3766 %                                                                             %
3767 %                                                                             %
3768 %                                                                             %
3769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3770 %
3771 %  MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3772 %  The method returns MagickTrue if the pixel region is masked, otherwise
3773 %  MagickFalse.
3774 %
3775 %  The format of the MaskPixelCacheNexus() method is:
3776 %
3777 %      MagickBooleanType MaskPixelCacheNexus(Image *image,
3778 %        NexusInfo *nexus_info,ExceptionInfo *exception)
3779 %
3780 %  A description of each parameter follows:
3781 %
3782 %    o image: the image.
3783 %
3784 %    o nexus_info: the cache nexus to clip.
3785 %
3786 %    o exception: return any errors or warnings in this structure.
3787 %
3788 */
3789
3790 static inline void MagickPixelCompositeMask(const PixelInfo *p,
3791   const MagickRealType alpha,const PixelInfo *q,
3792   const MagickRealType beta,PixelInfo *composite)
3793 {
3794   MagickRealType
3795     gamma;
3796
3797   if (alpha == TransparentAlpha)
3798     {
3799       *composite=(*q);
3800       return;
3801     }
3802   gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3803   gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3804   composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3805   composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3806   composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3807   if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3808     composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
3809 }
3810
3811 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3812   ExceptionInfo *exception)
3813 {
3814   CacheInfo
3815     *cache_info;
3816
3817   PixelInfo
3818     alpha,
3819     beta;
3820
3821   MagickSizeType
3822     number_pixels;
3823
3824   NexusInfo
3825     **clip_nexus,
3826     **image_nexus;
3827
3828   register const Quantum
3829     *restrict p,
3830     *restrict r;
3831
3832   register Quantum
3833     *restrict q;
3834
3835   register ssize_t
3836     i;
3837
3838   /*
3839     Apply clip mask.
3840   */
3841   if (image->debug != MagickFalse)
3842     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3843   if (image->mask == (Image *) NULL)
3844     return(MagickFalse);
3845   cache_info=(CacheInfo *) image->cache;
3846   if (cache_info == (Cache) NULL)
3847     return(MagickFalse);
3848   image_nexus=AcquirePixelCacheNexus(1);
3849   clip_nexus=AcquirePixelCacheNexus(1);
3850   if ((image_nexus == (NexusInfo **) NULL) ||
3851       (clip_nexus == (NexusInfo **) NULL))
3852     ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3853   p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3854     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3855     nexus_info->region.height,image_nexus[0],exception);
3856   q=nexus_info->pixels;
3857   r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3858     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3859     nexus_info->region.height,clip_nexus[0],&image->exception);
3860   GetPixelInfo(image,&alpha);
3861   GetPixelInfo(image,&beta);
3862   number_pixels=(MagickSizeType) nexus_info->region.width*
3863     nexus_info->region.height;
3864   for (i=0; i < (ssize_t) number_pixels; i++)
3865   {
3866     if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
3867       break;
3868     SetPixelInfo(image,p,&alpha);
3869     SetPixelInfo(image,q,&beta);
3870     MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3871       &alpha,alpha.alpha,&beta);
3872     SetPixelRed(image,ClampToQuantum(beta.red),q);
3873     SetPixelGreen(image,ClampToQuantum(beta.green),q);
3874     SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3875     if (cache_info->colorspace == CMYKColorspace)
3876       SetPixelBlack(image,ClampToQuantum(beta.black),q);
3877     SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
3878     p++;
3879     q++;
3880     r++;
3881   }
3882   clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3883   image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3884   if (i < (ssize_t) number_pixels)
3885     return(MagickFalse);
3886   return(MagickTrue);
3887 }
3888 \f
3889 /*
3890 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3891 %                                                                             %
3892 %                                                                             %
3893 %                                                                             %
3894 +   O p e n P i x e l C a c h e                                               %
3895 %                                                                             %
3896 %                                                                             %
3897 %                                                                             %
3898 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3899 %
3900 %  OpenPixelCache() allocates the pixel cache.  This includes defining the cache
3901 %  dimensions, allocating space for the image pixels and optionally the
3902 %  metacontent, and memory mapping the cache if it is disk based.  The cache
3903 %  nexus array is initialized as well.
3904 %
3905 %  The format of the OpenPixelCache() method is:
3906 %
3907 %      MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3908 %        ExceptionInfo *exception)
3909 %
3910 %  A description of each parameter follows:
3911 %
3912 %    o image: the image.
3913 %
3914 %    o mode: ReadMode, WriteMode, or IOMode.
3915 %
3916 %    o exception: return any errors or warnings in this structure.
3917 %
3918 */
3919
3920 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3921 {
3922   cache_info->mapped=MagickFalse;
3923   cache_info->pixels=(Quantum *) AcquireAlignedMemory(1,(size_t)
3924     cache_info->length);
3925   if (cache_info->pixels == (Quantum *) NULL)
3926     {
3927       cache_info->mapped=MagickTrue;
3928       cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3929         cache_info->length);
3930     }
3931 }
3932
3933 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3934 {
3935   CacheInfo
3936     *cache_info;
3937
3938   MagickOffsetType
3939     count,
3940     extent,
3941     offset;
3942
3943   cache_info=(CacheInfo *) image->cache;
3944   if (image->debug != MagickFalse)
3945     {
3946       char
3947         format[MaxTextExtent],
3948         message[MaxTextExtent];
3949
3950       (void) FormatMagickSize(length,MagickFalse,format);
3951       (void) FormatLocaleString(message,MaxTextExtent,
3952         "extend %s (%s[%d], disk, %s)",cache_info->filename,
3953         cache_info->cache_filename,cache_info->file,format);
3954       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3955     }
3956   if (length != (MagickSizeType) ((MagickOffsetType) length))
3957     return(MagickFalse);
3958   extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3959   if (extent < 0)
3960     return(MagickFalse);
3961   if ((MagickSizeType) extent >= length)
3962     return(MagickTrue);
3963   offset=(MagickOffsetType) length-1;
3964   count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3965   return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3966 }
3967
3968 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3969   ExceptionInfo *exception)
3970 {
3971   CacheInfo
3972     *cache_info,
3973     source_info;
3974
3975   char
3976     format[MaxTextExtent],
3977     message[MaxTextExtent];
3978
3979   MagickBooleanType
3980     status;
3981
3982   MagickSizeType
3983     length,
3984     number_pixels;
3985
3986   size_t
3987     columns,
3988     packet_size;
3989
3990   assert(image != (const Image *) NULL);
3991   assert(image->signature == MagickSignature);
3992   assert(image->cache != (Cache) NULL);
3993   if (image->debug != MagickFalse)
3994     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3995   if ((image->columns == 0) || (image->rows == 0))
3996     ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3997   StandardPixelChannelMap(image);
3998   cache_info=(CacheInfo *) image->cache;
3999   assert(cache_info->signature == MagickSignature);
4000   source_info=(*cache_info);
4001   source_info.file=(-1);
4002   (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4003     image->filename,(double) GetImageIndexInList(image));
4004   cache_info->storage_class=image->storage_class;
4005   cache_info->colorspace=image->colorspace;
4006   cache_info->mode=mode;
4007   cache_info->rows=image->rows;
4008   cache_info->columns=image->columns;
4009   cache_info->number_channels=GetPixelChannels(image);
4010   cache_info->metacontent_extent=image->metacontent_extent;
4011   if (image->ping != MagickFalse)
4012     {
4013       cache_info->type=PingCache;
4014       cache_info->pixels=(Quantum *) NULL;
4015       cache_info->metacontent=(void *) NULL;
4016       cache_info->length=0;
4017       return(MagickTrue);
4018     }
4019   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4020   packet_size=cache_info->number_channels*sizeof(Quantum);
4021   if (image->metacontent_extent != 0)
4022     packet_size+=cache_info->metacontent_extent;
4023   length=number_pixels*packet_size;
4024   columns=(size_t) (length/cache_info->rows/packet_size);
4025   if (cache_info->columns != columns)
4026     ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4027       image->filename);
4028   cache_info->length=length;
4029   if ((cache_info->type != UndefinedCache) &&
4030       (cache_info->columns <= source_info.columns) &&
4031       (cache_info->rows <= source_info.rows) &&
4032       (cache_info->number_channels <= source_info.number_channels) &&
4033       (cache_info->metacontent_extent <= source_info.metacontent_extent))
4034     {
4035       /*
4036         Inline pixel cache clone optimization.
4037       */
4038       if ((cache_info->columns == source_info.columns) &&
4039           (cache_info->rows == source_info.rows) &&
4040           (cache_info->number_channels == source_info.number_channels) &&
4041           (cache_info->metacontent_extent == source_info.metacontent_extent))
4042         return(MagickTrue);
4043       return(ClonePixelCachePixels(cache_info,&source_info,exception));
4044     }
4045   status=AcquireMagickResource(AreaResource,cache_info->length);
4046   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4047     cache_info->metacontent_extent);
4048   if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4049     {
4050       status=AcquireMagickResource(MemoryResource,cache_info->length);
4051       if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4052           (cache_info->type == MemoryCache))
4053         {
4054           AllocatePixelCachePixels(cache_info);
4055           if (cache_info->pixels == (Quantum *) NULL)
4056             cache_info->pixels=source_info.pixels;
4057           else
4058             {
4059               /*
4060                 Create memory pixel cache.
4061               */
4062               status=MagickTrue;
4063               if (image->debug != MagickFalse)
4064                 {
4065                   (void) FormatMagickSize(cache_info->length,MagickTrue,
4066                     format);
4067                   (void) FormatLocaleString(message,MaxTextExtent,
4068                     "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4069                     cache_info->filename,cache_info->mapped != MagickFalse ?
4070                     "anonymous" : "heap",(double) cache_info->columns,(double)
4071                     cache_info->rows,(double) cache_info->number_channels,
4072                     format);
4073                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4074                     message);
4075                 }
4076               cache_info->type=MemoryCache;
4077               cache_info->metacontent=(void *) NULL;
4078               if (cache_info->metacontent_extent != 0)
4079                 cache_info->metacontent=(void *) (cache_info->pixels+
4080                   number_pixels*cache_info->number_channels);
4081               if (source_info.storage_class != UndefinedClass)
4082                 {
4083                   status=ClonePixelCachePixels(cache_info,&source_info,
4084                     exception);
4085                   RelinquishPixelCachePixels(&source_info);
4086                 }
4087               return(status);
4088             }
4089         }
4090       RelinquishMagickResource(MemoryResource,cache_info->length);
4091     }
4092   /*
4093     Create pixel cache on disk.
4094   */
4095   status=AcquireMagickResource(DiskResource,cache_info->length);
4096   if (status == MagickFalse)
4097     {
4098       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4099         "CacheResourcesExhausted","`%s'",image->filename);
4100       return(MagickFalse);
4101     }
4102   if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4103     {
4104       RelinquishMagickResource(DiskResource,cache_info->length);
4105       ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4106         image->filename);
4107       return(MagickFalse);
4108     }
4109   status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4110     cache_info->length);
4111   if (status == MagickFalse)
4112     {
4113       ThrowFileException(exception,CacheError,"UnableToExtendCache",
4114         image->filename);
4115       return(MagickFalse);
4116     }
4117   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4118     cache_info->metacontent_extent);
4119   status=AcquireMagickResource(AreaResource,cache_info->length);
4120   if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4121     cache_info->type=DiskCache;
4122   else
4123     {
4124       status=AcquireMagickResource(MapResource,cache_info->length);
4125       if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4126           (cache_info->type != MemoryCache))
4127         cache_info->type=DiskCache;
4128       else
4129         {
4130           cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4131             cache_info->offset,(size_t) cache_info->length);
4132           if (cache_info->pixels == (Quantum *) NULL)
4133             {
4134               cache_info->type=DiskCache;
4135               cache_info->pixels=source_info.pixels;
4136             }
4137           else
4138             {
4139               /*
4140                 Create file-backed memory-mapped pixel cache.
4141               */
4142               status=MagickTrue;
4143               (void) ClosePixelCacheOnDisk(cache_info);
4144               cache_info->type=MapCache;
4145               cache_info->mapped=MagickTrue;
4146               cache_info->metacontent=(void *) NULL;
4147               if (cache_info->metacontent_extent != 0)
4148                 cache_info->metacontent=(void *) (cache_info->pixels+
4149                   number_pixels*cache_info->number_channels);
4150               if (source_info.storage_class != UndefinedClass)
4151                 {
4152                   status=ClonePixelCachePixels(cache_info,&source_info,
4153                     exception);
4154                   RelinquishPixelCachePixels(&source_info);
4155                 }
4156               if (image->debug != MagickFalse)
4157                 {
4158                   (void) FormatMagickSize(cache_info->length,MagickTrue,
4159                     format);
4160                   (void) FormatLocaleString(message,MaxTextExtent,
4161                     "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4162                     cache_info->filename,cache_info->cache_filename,
4163                     cache_info->file,(double) cache_info->columns,(double)
4164                     cache_info->rows,(double) cache_info->number_channels,
4165                     format);
4166                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4167                     message);
4168                 }
4169               return(status);
4170             }
4171         }
4172       RelinquishMagickResource(MapResource,cache_info->length);
4173     }
4174   status=MagickTrue;
4175   if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4176     {
4177       status=ClonePixelCachePixels(cache_info,&source_info,exception);
4178       RelinquishPixelCachePixels(&source_info);
4179     }
4180   if (image->debug != MagickFalse)
4181     {
4182       (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4183       (void) FormatLocaleString(message,MaxTextExtent,
4184         "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4185         cache_info->cache_filename,cache_info->file,(double)
4186         cache_info->columns,(double) cache_info->rows,(double)
4187         cache_info->number_channels,format);
4188       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4189     }
4190   return(status);
4191 }
4192 \f
4193 /*
4194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4195 %                                                                             %
4196 %                                                                             %
4197 %                                                                             %
4198 +   P e r s i s t P i x e l C a c h e                                         %
4199 %                                                                             %
4200 %                                                                             %
4201 %                                                                             %
4202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4203 %
4204 %  PersistPixelCache() attaches to or initializes a persistent pixel cache.  A
4205 %  persistent pixel cache is one that resides on disk and is not destroyed
4206 %  when the program exits.
4207 %
4208 %  The format of the PersistPixelCache() method is:
4209 %
4210 %      MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4211 %        const MagickBooleanType attach,MagickOffsetType *offset,
4212 %        ExceptionInfo *exception)
4213 %
4214 %  A description of each parameter follows:
4215 %
4216 %    o image: the image.
4217 %
4218 %    o filename: the persistent pixel cache filename.
4219 %
4220 %    o attach: A value other than zero initializes the persistent pixel cache.
4221 %
4222 %    o initialize: A value other than zero initializes the persistent pixel
4223 %      cache.
4224 %
4225 %    o offset: the offset in the persistent cache to store pixels.
4226 %
4227 %    o exception: return any errors or warnings in this structure.
4228 %
4229 */
4230 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4231   const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4232   ExceptionInfo *exception)
4233 {
4234   CacheInfo
4235     *cache_info,
4236     *clone_info;
4237
4238   Image
4239     clone_image;
4240
4241   MagickBooleanType
4242     status;
4243
4244   ssize_t
4245     page_size;
4246
4247   assert(image != (Image *) NULL);
4248   assert(image->signature == MagickSignature);
4249   if (image->debug != MagickFalse)
4250     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4251   assert(image->cache != (void *) NULL);
4252   assert(filename != (const char *) NULL);
4253   assert(offset != (MagickOffsetType *) NULL);
4254   page_size=GetMagickPageSize();
4255   cache_info=(CacheInfo *) image->cache;
4256   assert(cache_info->signature == MagickSignature);
4257   if (attach != MagickFalse)
4258     {
4259       /*
4260         Attach existing persistent pixel cache.
4261       */
4262       if (image->debug != MagickFalse)
4263         (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4264           "attach persistent cache");
4265       (void) CopyMagickString(cache_info->cache_filename,filename,
4266         MaxTextExtent);
4267       cache_info->type=DiskCache;
4268       cache_info->offset=(*offset);
4269       if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4270         return(MagickFalse);
4271       *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4272       return(MagickTrue);
4273     }
4274   if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4275       (cache_info->reference_count == 1))
4276     {
4277       LockSemaphoreInfo(cache_info->semaphore);
4278       if ((cache_info->mode != ReadMode) &&
4279           (cache_info->type != MemoryCache) &&
4280           (cache_info->reference_count == 1))
4281         {
4282           int
4283             status;
4284
4285           /*
4286             Usurp existing persistent pixel cache.
4287           */
4288           status=rename(cache_info->cache_filename,filename);
4289           if (status == 0)
4290             {
4291               (void) CopyMagickString(cache_info->cache_filename,filename,
4292                 MaxTextExtent);
4293               *offset+=cache_info->length+page_size-(cache_info->length %
4294                 page_size);
4295               UnlockSemaphoreInfo(cache_info->semaphore);
4296               cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4297               if (image->debug != MagickFalse)
4298                 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4299                   "Usurp resident persistent cache");
4300               return(MagickTrue);
4301             }
4302         }
4303       UnlockSemaphoreInfo(cache_info->semaphore);
4304     }
4305   /*
4306     Clone persistent pixel cache.
4307   */
4308   clone_image=(*image);
4309   clone_info=(CacheInfo *) clone_image.cache;
4310   image->cache=ClonePixelCache(cache_info);
4311   cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4312   (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4313   cache_info->type=DiskCache;
4314   cache_info->offset=(*offset);
4315   cache_info=(CacheInfo *) image->cache;
4316   status=OpenPixelCache(image,IOMode,exception);
4317   if (status != MagickFalse)
4318     status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4319   *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4320   clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4321   return(status);
4322 }
4323 \f
4324 /*
4325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4326 %                                                                             %
4327 %                                                                             %
4328 %                                                                             %
4329 +   Q u e u e A u t h e n t i c N e x u s                                     %
4330 %                                                                             %
4331 %                                                                             %
4332 %                                                                             %
4333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4334 %
4335 %  QueueAuthenticNexus() allocates an region to store image pixels as defined
4336 %  by the region rectangle and returns a pointer to the region.  This region is
4337 %  subsequently transferred from the pixel cache with
4338 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4339 %  pixels are transferred, otherwise a NULL is returned.
4340 %
4341 %  The format of the QueueAuthenticNexus() method is:
4342 %
4343 %      Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4344 %        const ssize_t y,const size_t columns,const size_t rows,
4345 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4346 %
4347 %  A description of each parameter follows:
4348 %
4349 %    o image: the image.
4350 %
4351 %    o x,y,columns,rows:  These values define the perimeter of a region of
4352 %      pixels.
4353 %
4354 %    o nexus_info: the cache nexus to set.
4355 %
4356 %    o exception: return any errors or warnings in this structure.
4357 %
4358 */
4359 MagickExport Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4360   const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4361   ExceptionInfo *exception)
4362 {
4363   CacheInfo
4364     *cache_info;
4365
4366   MagickOffsetType
4367     offset;
4368
4369   MagickSizeType
4370     number_pixels;
4371
4372   RectangleInfo
4373     region;
4374
4375   /*
4376     Validate pixel cache geometry.
4377   */
4378   assert(image != (const Image *) NULL);
4379   assert(image->signature == MagickSignature);
4380   assert(image->cache != (Cache) NULL);
4381   cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4382   assert(cache_info->signature == MagickSignature);
4383   if (cache_info == (Cache) NULL)
4384     return((Quantum *) NULL);
4385   if ((cache_info->columns == 0) && (cache_info->rows == 0))
4386     {
4387       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4388         "NoPixelsDefinedInCache","`%s'",image->filename);
4389       return((Quantum *) NULL);
4390     }
4391   if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4392       (y >= (ssize_t) cache_info->rows))
4393     {
4394       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4395         "PixelsAreNotAuthentic","`%s'",image->filename);
4396       return((Quantum *) NULL);
4397     }
4398   offset=(MagickOffsetType) y*cache_info->columns+x;
4399   if (offset < 0)
4400     return((Quantum *) NULL);
4401   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4402   offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4403   if ((MagickSizeType) offset >= number_pixels)
4404     return((Quantum *) NULL);
4405   /*
4406     Return pixel cache.
4407   */
4408   region.x=x;
4409   region.y=y;
4410   region.width=columns;
4411   region.height=rows;
4412   return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4413 }
4414 \f
4415 /*
4416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4417 %                                                                             %
4418 %                                                                             %
4419 %                                                                             %
4420 +   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                         %
4421 %                                                                             %
4422 %                                                                             %
4423 %                                                                             %
4424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4425 %
4426 %  QueueAuthenticPixelsCache() allocates an region to store image pixels as
4427 %  defined by the region rectangle and returns a pointer to the region.  This
4428 %  region is subsequently transferred from the pixel cache with
4429 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4430 %  pixels are transferred, otherwise a NULL is returned.
4431 %
4432 %  The format of the QueueAuthenticPixelsCache() method is:
4433 %
4434 %      Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4435 %        const ssize_t y,const size_t columns,const size_t rows,
4436 %        ExceptionInfo *exception)
4437 %
4438 %  A description of each parameter follows:
4439 %
4440 %    o image: the image.
4441 %
4442 %    o x,y,columns,rows:  These values define the perimeter of a region of
4443 %      pixels.
4444 %
4445 %    o exception: return any errors or warnings in this structure.
4446 %
4447 */
4448 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4449   const ssize_t y,const size_t columns,const size_t rows,
4450   ExceptionInfo *exception)
4451 {
4452   CacheInfo
4453     *cache_info;
4454
4455   const int
4456     id = GetOpenMPThreadId();
4457
4458   Quantum
4459     *pixels;
4460
4461   assert(image != (const Image *) NULL);
4462   assert(image->signature == MagickSignature);
4463   assert(image->cache != (Cache) NULL);
4464   cache_info=(CacheInfo *) image->cache;
4465   assert(cache_info->signature == MagickSignature);
4466   assert(id < (int) cache_info->number_threads);
4467   pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4468     exception);
4469   return(pixels);
4470 }
4471 \f
4472 /*
4473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4474 %                                                                             %
4475 %                                                                             %
4476 %                                                                             %
4477 %   Q u e u e A u t h e n t i c P i x e l s                                   %
4478 %                                                                             %
4479 %                                                                             %
4480 %                                                                             %
4481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4482 %
4483 %  QueueAuthenticPixels() queues a mutable pixel region.  If the region is
4484 %  successfully initialized a pointer to a Quantum array representing the
4485 %  region is returned, otherwise NULL is returned.  The returned pointer may
4486 %  point to a temporary working buffer for the pixels or it may point to the
4487 %  final location of the pixels in memory.
4488 %
4489 %  Write-only access means that any existing pixel values corresponding to
4490 %  the region are ignored.  This is useful if the initial image is being
4491 %  created from scratch, or if the existing pixel values are to be
4492 %  completely replaced without need to refer to their pre-existing values.
4493 %  The application is free to read and write the pixel buffer returned by
4494 %  QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4495 %  initialize the pixel array values. Initializing pixel array values is the
4496 %  application's responsibility.
4497 %
4498 %  Performance is maximized if the selected region is part of one row, or
4499 %  one or more full rows, since then there is opportunity to access the
4500 %  pixels in-place (without a copy) if the image is in memory, or in a
4501 %  memory-mapped file. The returned pointer must *never* be deallocated
4502 %  by the user.
4503 %
4504 %  Pixels accessed via the returned pointer represent a simple array of type
4505 %  Quantum. If the image type is CMYK or the storage class is PseudoClass,
4506 %  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4507 %  obtain the meta-content (of type void) corresponding to the region.
4508 %  Once the Quantum (and/or Quantum) array has been updated, the
4509 %  changes must be saved back to the underlying image using
4510 %  SyncAuthenticPixels() or they may be lost.
4511 %
4512 %  The format of the QueueAuthenticPixels() method is:
4513 %
4514 %      Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4515 %        const ssize_t y,const size_t columns,const size_t rows,
4516 %        ExceptionInfo *exception)
4517 %
4518 %  A description of each parameter follows:
4519 %
4520 %    o image: the image.
4521 %
4522 %    o x,y,columns,rows:  These values define the perimeter of a region of
4523 %      pixels.
4524 %
4525 %    o exception: return any errors or warnings in this structure.
4526 %
4527 */
4528 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4529   const ssize_t y,const size_t columns,const size_t rows,
4530   ExceptionInfo *exception)
4531 {
4532   CacheInfo
4533     *cache_info;
4534
4535   const int
4536     id = GetOpenMPThreadId();
4537
4538   Quantum
4539     *pixels;
4540
4541   assert(image != (Image *) NULL);
4542   assert(image->signature == MagickSignature);
4543   assert(image->cache != (Cache) NULL);
4544   cache_info=(CacheInfo *) image->cache;
4545   assert(cache_info->signature == MagickSignature);
4546   if (cache_info->methods.queue_authentic_pixels_handler !=
4547        (QueueAuthenticPixelsHandler) NULL)
4548     {
4549       pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4550         columns,rows,exception);
4551       return(pixels);
4552     }
4553   assert(id < (int) cache_info->number_threads);
4554   pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4555     exception);
4556   return(pixels);
4557 }
4558 \f
4559 /*
4560 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4561 %                                                                             %
4562 %                                                                             %
4563 %                                                                             %
4564 +   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                         %
4565 %                                                                             %
4566 %                                                                             %
4567 %                                                                             %
4568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4569 %
4570 %  ReadPixelCacheMetacontent() reads metacontent from the specified region of
4571 %  the pixel cache.
4572 %
4573 %  The format of the ReadPixelCacheMetacontent() method is:
4574 %
4575 %      MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4576 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4577 %
4578 %  A description of each parameter follows:
4579 %
4580 %    o cache_info: the pixel cache.
4581 %
4582 %    o nexus_info: the cache nexus to read the metacontent.
4583 %
4584 %    o exception: return any errors or warnings in this structure.
4585 %
4586 */
4587 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4588   NexusInfo *nexus_info,ExceptionInfo *exception)
4589 {
4590   MagickOffsetType
4591     count,
4592     offset;
4593
4594   MagickSizeType
4595     extent,
4596     length;
4597
4598   register ssize_t
4599     y;
4600
4601   register unsigned char
4602     *restrict q;
4603
4604   size_t
4605     rows;
4606
4607   if (cache_info->metacontent_extent == 0)
4608     return(MagickFalse);
4609   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4610     return(MagickTrue);
4611   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4612     nexus_info->region.x;
4613   length=(MagickSizeType) nexus_info->region.width*
4614     cache_info->metacontent_extent;
4615   rows=nexus_info->region.height;
4616   extent=length*rows;
4617   q=(unsigned char *) nexus_info->metacontent;
4618   switch (cache_info->type)
4619   {
4620     case MemoryCache:
4621     case MapCache:
4622     {
4623       register unsigned char
4624         *restrict p;
4625
4626       /*
4627         Read meta-content from memory.
4628       */
4629       if ((cache_info->columns == nexus_info->region.width) &&
4630           (extent == (MagickSizeType) ((size_t) extent)))
4631         {
4632           length=extent;
4633           rows=1UL;
4634         }
4635       p=(unsigned char *) cache_info->metacontent+offset*
4636         cache_info->metacontent_extent;
4637       for (y=0; y < (ssize_t) rows; y++)
4638       {
4639         (void) memcpy(q,p,(size_t) length);
4640         p+=cache_info->metacontent_extent*cache_info->columns;
4641         q+=cache_info->metacontent_extent*nexus_info->region.width;
4642       }
4643       break;
4644     }
4645     case DiskCache:
4646     {
4647       /*
4648         Read meta content from disk.
4649       */
4650       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4651         {
4652           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4653             cache_info->cache_filename);
4654           return(MagickFalse);
4655         }
4656       if ((cache_info->columns == nexus_info->region.width) &&
4657           (extent <= MagickMaxBufferExtent))
4658         {
4659           length=extent;
4660           rows=1UL;
4661         }
4662       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4663       for (y=0; y < (ssize_t) rows; y++)
4664       {
4665         count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4666           cache_info->number_channels*sizeof(Quantum)+offset*
4667           cache_info->metacontent_extent,length,(unsigned char *) q);
4668         if ((MagickSizeType) count != length)
4669           break;
4670         offset+=cache_info->columns;
4671         q+=cache_info->metacontent_extent*nexus_info->region.width;
4672       }
4673       if (y < (ssize_t) rows)
4674         {
4675           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4676             cache_info->cache_filename);
4677           return(MagickFalse);
4678         }
4679       break;
4680     }
4681     default:
4682       break;
4683   }
4684   if ((cache_info->debug != MagickFalse) &&
4685       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4686     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4687       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4688       nexus_info->region.width,(double) nexus_info->region.height,(double)
4689       nexus_info->region.x,(double) nexus_info->region.y);
4690   return(MagickTrue);
4691 }
4692 \f
4693 /*
4694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4695 %                                                                             %
4696 %                                                                             %
4697 %                                                                             %
4698 +   R e a d P i x e l C a c h e P i x e l s                                   %
4699 %                                                                             %
4700 %                                                                             %
4701 %                                                                             %
4702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703 %
4704 %  ReadPixelCachePixels() reads pixels from the specified region of the pixel
4705 %  cache.
4706 %
4707 %  The format of the ReadPixelCachePixels() method is:
4708 %
4709 %      MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4710 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4711 %
4712 %  A description of each parameter follows:
4713 %
4714 %    o cache_info: the pixel cache.
4715 %
4716 %    o nexus_info: the cache nexus to read the pixels.
4717 %
4718 %    o exception: return any errors or warnings in this structure.
4719 %
4720 */
4721 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4722   NexusInfo *nexus_info,ExceptionInfo *exception)
4723 {
4724   MagickOffsetType
4725     count,
4726     offset;
4727
4728   MagickSizeType
4729     extent,
4730     length;
4731
4732   register Quantum
4733     *restrict q;
4734
4735   register ssize_t
4736     y;
4737
4738   size_t
4739     rows;
4740
4741   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4742     return(MagickTrue);
4743   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4744     nexus_info->region.x;
4745   length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4746     sizeof(Quantum);
4747   rows=nexus_info->region.height;
4748   extent=length*rows;
4749   q=nexus_info->pixels;
4750   switch (cache_info->type)
4751   {
4752     case MemoryCache:
4753     case MapCache:
4754     {
4755       register Quantum
4756         *restrict p;
4757
4758       /*
4759         Read pixels from memory.
4760       */
4761       if ((cache_info->columns == nexus_info->region.width) &&
4762           (extent == (MagickSizeType) ((size_t) extent)))
4763         {
4764           length=extent;
4765           rows=1UL;
4766         }
4767       p=cache_info->pixels+offset*cache_info->number_channels;
4768       for (y=0; y < (ssize_t) rows; y++)
4769       {
4770         (void) memcpy(q,p,(size_t) length);
4771         p+=cache_info->number_channels*cache_info->columns;
4772         q+=cache_info->number_channels*nexus_info->region.width;
4773       }
4774       break;
4775     }
4776     case DiskCache:
4777     {
4778       /*
4779         Read pixels from disk.
4780       */
4781       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4782         {
4783           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4784             cache_info->cache_filename);
4785           return(MagickFalse);
4786         }
4787       if ((cache_info->columns == nexus_info->region.width) &&
4788           (extent <= MagickMaxBufferExtent))
4789         {
4790           length=extent;
4791           rows=1UL;
4792         }
4793       for (y=0; y < (ssize_t) rows; y++)
4794       {
4795         count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4796           cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4797         if ((MagickSizeType) count != length)
4798           break;
4799         offset+=cache_info->columns;
4800         q+=cache_info->number_channels*nexus_info->region.width;
4801       }
4802       if (y < (ssize_t) rows)
4803         {
4804           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4805             cache_info->cache_filename);
4806           return(MagickFalse);
4807         }
4808       break;
4809     }
4810     default:
4811       break;
4812   }
4813   if ((cache_info->debug != MagickFalse) &&
4814       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4815     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4816       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4817       nexus_info->region.width,(double) nexus_info->region.height,(double)
4818       nexus_info->region.x,(double) nexus_info->region.y);
4819   return(MagickTrue);
4820 }
4821 \f
4822 /*
4823 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4824 %                                                                             %
4825 %                                                                             %
4826 %                                                                             %
4827 +   R e f e r e n c e P i x e l C a c h e                                     %
4828 %                                                                             %
4829 %                                                                             %
4830 %                                                                             %
4831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4832 %
4833 %  ReferencePixelCache() increments the reference count associated with the
4834 %  pixel cache returning a pointer to the cache.
4835 %
4836 %  The format of the ReferencePixelCache method is:
4837 %
4838 %      Cache ReferencePixelCache(Cache cache_info)
4839 %
4840 %  A description of each parameter follows:
4841 %
4842 %    o cache_info: the pixel cache.
4843 %
4844 */
4845 MagickExport Cache ReferencePixelCache(Cache cache)
4846 {
4847   CacheInfo
4848     *cache_info;
4849
4850   assert(cache != (Cache *) NULL);
4851   cache_info=(CacheInfo *) cache;
4852   assert(cache_info->signature == MagickSignature);
4853   LockSemaphoreInfo(cache_info->semaphore);
4854   cache_info->reference_count++;
4855   UnlockSemaphoreInfo(cache_info->semaphore);
4856   return(cache_info);
4857 }
4858 \f
4859 /*
4860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4861 %                                                                             %
4862 %                                                                             %
4863 %                                                                             %
4864 +   S e t P i x e l C a c h e M e t h o d s                                   %
4865 %                                                                             %
4866 %                                                                             %
4867 %                                                                             %
4868 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4869 %
4870 %  SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4871 %
4872 %  The format of the SetPixelCacheMethods() method is:
4873 %
4874 %      SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4875 %
4876 %  A description of each parameter follows:
4877 %
4878 %    o cache: the pixel cache.
4879 %
4880 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
4881 %
4882 */
4883 MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4884 {
4885   CacheInfo
4886     *cache_info;
4887
4888   GetOneAuthenticPixelFromHandler
4889     get_one_authentic_pixel_from_handler;
4890
4891   GetOneVirtualPixelFromHandler
4892     get_one_virtual_pixel_from_handler;
4893
4894   /*
4895     Set cache pixel methods.
4896   */
4897   assert(cache != (Cache) NULL);
4898   assert(cache_methods != (CacheMethods *) NULL);
4899   cache_info=(CacheInfo *) cache;
4900   assert(cache_info->signature == MagickSignature);
4901   if (cache_info->debug != MagickFalse)
4902     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4903       cache_info->filename);
4904   if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4905     cache_info->methods.get_virtual_pixel_handler=
4906       cache_methods->get_virtual_pixel_handler;
4907   if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4908     cache_info->methods.destroy_pixel_handler=
4909       cache_methods->destroy_pixel_handler;
4910   if (cache_methods->get_virtual_metacontent_from_handler !=
4911       (GetVirtualMetacontentFromHandler) NULL)
4912     cache_info->methods.get_virtual_metacontent_from_handler=
4913       cache_methods->get_virtual_metacontent_from_handler;
4914   if (cache_methods->get_authentic_pixels_handler !=
4915       (GetAuthenticPixelsHandler) NULL)
4916     cache_info->methods.get_authentic_pixels_handler=
4917       cache_methods->get_authentic_pixels_handler;
4918   if (cache_methods->queue_authentic_pixels_handler !=
4919       (QueueAuthenticPixelsHandler) NULL)
4920     cache_info->methods.queue_authentic_pixels_handler=
4921       cache_methods->queue_authentic_pixels_handler;
4922   if (cache_methods->sync_authentic_pixels_handler !=
4923       (SyncAuthenticPixelsHandler) NULL)
4924     cache_info->methods.sync_authentic_pixels_handler=
4925       cache_methods->sync_authentic_pixels_handler;
4926   if (cache_methods->get_authentic_pixels_from_handler !=
4927       (GetAuthenticPixelsFromHandler) NULL)
4928     cache_info->methods.get_authentic_pixels_from_handler=
4929       cache_methods->get_authentic_pixels_from_handler;
4930   if (cache_methods->get_authentic_metacontent_from_handler !=
4931       (GetAuthenticMetacontentFromHandler) NULL)
4932     cache_info->methods.get_authentic_metacontent_from_handler=
4933       cache_methods->get_authentic_metacontent_from_handler;
4934   get_one_virtual_pixel_from_handler=
4935     cache_info->methods.get_one_virtual_pixel_from_handler;
4936   if (get_one_virtual_pixel_from_handler !=
4937       (GetOneVirtualPixelFromHandler) NULL)
4938     cache_info->methods.get_one_virtual_pixel_from_handler=
4939       cache_methods->get_one_virtual_pixel_from_handler;
4940   get_one_authentic_pixel_from_handler=
4941     cache_methods->get_one_authentic_pixel_from_handler;
4942   if (get_one_authentic_pixel_from_handler !=
4943       (GetOneAuthenticPixelFromHandler) NULL)
4944     cache_info->methods.get_one_authentic_pixel_from_handler=
4945       cache_methods->get_one_authentic_pixel_from_handler;
4946 }
4947 \f
4948 /*
4949 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4950 %                                                                             %
4951 %                                                                             %
4952 %                                                                             %
4953 +   S e t P i x e l C a c h e N e x u s P i x e l s                           %
4954 %                                                                             %
4955 %                                                                             %
4956 %                                                                             %
4957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4958 %
4959 %  SetPixelCacheNexusPixels() defines the region of the cache for the
4960 %  specified cache nexus.
4961 %
4962 %  The format of the SetPixelCacheNexusPixels() method is:
4963 %
4964 %      Quantum SetPixelCacheNexusPixels(const Image *image,
4965 %        const RectangleInfo *region,NexusInfo *nexus_info,
4966 %        ExceptionInfo *exception)
4967 %
4968 %  A description of each parameter follows:
4969 %
4970 %    o image: the image.
4971 %
4972 %    o region: A pointer to the RectangleInfo structure that defines the
4973 %      region of this particular cache nexus.
4974 %
4975 %    o nexus_info: the cache nexus to set.
4976 %
4977 %    o exception: return any errors or warnings in this structure.
4978 %
4979 */
4980
4981 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4982   NexusInfo *nexus_info,ExceptionInfo *exception)
4983 {
4984   if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4985     return(MagickFalse);
4986   nexus_info->mapped=MagickFalse;
4987   nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
4988     nexus_info->length);
4989   if (nexus_info->cache == (Quantum *) NULL)
4990     {
4991       nexus_info->mapped=MagickTrue;
4992       nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4993         nexus_info->length);
4994     }
4995   if (nexus_info->cache == (Quantum *) NULL)
4996     {
4997       (void) ThrowMagickException(exception,GetMagickModule(),
4998         ResourceLimitError,"MemoryAllocationFailed","`%s'",
4999         cache_info->filename);
5000       return(MagickFalse);
5001     }
5002   return(MagickTrue);
5003 }
5004
5005 static Quantum *SetPixelCacheNexusPixels(const Image *image,
5006   const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5007 {
5008   CacheInfo
5009     *cache_info;
5010
5011   MagickBooleanType
5012     status;
5013
5014   MagickSizeType
5015     length,
5016     number_pixels;
5017
5018   cache_info=(CacheInfo *) image->cache;
5019   assert(cache_info->signature == MagickSignature);
5020   if (cache_info->type == UndefinedCache)
5021     return((Quantum *) NULL);
5022   nexus_info->region=(*region);
5023   if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5024       (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5025     {
5026       ssize_t
5027         x,
5028         y;
5029
5030       x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5031       y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5032       if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5033            (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5034           ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5035            ((nexus_info->region.width == cache_info->columns) ||
5036             ((nexus_info->region.width % cache_info->columns) == 0)))))
5037         {
5038           MagickOffsetType
5039             offset;
5040
5041           /*
5042             Pixels are accessed directly from memory.
5043           */
5044           offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5045             nexus_info->region.x;
5046           nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5047             offset;
5048           nexus_info->metacontent=(void *) NULL;
5049           if (cache_info->metacontent_extent != 0)
5050             nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5051               offset*cache_info->metacontent_extent;
5052           return(nexus_info->pixels);
5053         }
5054     }
5055   /*
5056     Pixels are stored in a cache region until they are synced to the cache.
5057   */
5058   number_pixels=(MagickSizeType) nexus_info->region.width*
5059     nexus_info->region.height;
5060   length=number_pixels*cache_info->number_channels*sizeof(Quantum);
5061   if (cache_info->metacontent_extent != 0)
5062     length+=number_pixels*cache_info->metacontent_extent;
5063   if (nexus_info->cache == (Quantum *) NULL)
5064     {
5065       nexus_info->length=length;
5066       status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5067       if (status == MagickFalse)
5068         {
5069           nexus_info->length=0;
5070           return((Quantum *) NULL);
5071         }
5072     }
5073   else
5074     if (nexus_info->length != length)
5075       {
5076         RelinquishCacheNexusPixels(nexus_info);
5077         nexus_info->length=length;
5078         status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5079         if (status == MagickFalse)
5080           {
5081             nexus_info->length=0;
5082             return((Quantum *) NULL);
5083           }
5084       }
5085   nexus_info->pixels=nexus_info->cache;
5086   nexus_info->metacontent=(void *) NULL;
5087   if (cache_info->metacontent_extent != 0)
5088     nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
5089       cache_info->number_channels);
5090   return(nexus_info->pixels);
5091 }
5092 \f
5093 /*
5094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5095 %                                                                             %
5096 %                                                                             %
5097 %                                                                             %
5098 %   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                       %
5099 %                                                                             %
5100 %                                                                             %
5101 %                                                                             %
5102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5103 %
5104 %  SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5105 %  pixel cache and returns the previous setting.  A virtual pixel is any pixel
5106 %  access that is outside the boundaries of the image cache.
5107 %
5108 %  The format of the SetPixelCacheVirtualMethod() method is:
5109 %
5110 %      VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5111 %        const VirtualPixelMethod virtual_pixel_method)
5112 %
5113 %  A description of each parameter follows:
5114 %
5115 %    o image: the image.
5116 %
5117 %    o virtual_pixel_method: choose the type of virtual pixel.
5118 %
5119 */
5120 MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5121   const VirtualPixelMethod virtual_pixel_method)
5122 {
5123   CacheInfo
5124     *cache_info;
5125
5126   VirtualPixelMethod
5127     method;
5128
5129   assert(image != (Image *) NULL);
5130   assert(image->signature == MagickSignature);
5131   if (image->debug != MagickFalse)
5132     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5133   assert(image->cache != (Cache) NULL);
5134   cache_info=(CacheInfo *) image->cache;
5135   assert(cache_info->signature == MagickSignature);
5136   method=cache_info->virtual_pixel_method;
5137   cache_info->virtual_pixel_method=virtual_pixel_method;
5138   return(method);
5139 }
5140 \f
5141 /*
5142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5143 %                                                                             %
5144 %                                                                             %
5145 %                                                                             %
5146 +   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                   %
5147 %                                                                             %
5148 %                                                                             %
5149 %                                                                             %
5150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5151 %
5152 %  SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5153 %  in-memory or disk cache.  The method returns MagickTrue if the pixel region
5154 %  is synced, otherwise MagickFalse.
5155 %
5156 %  The format of the SyncAuthenticPixelCacheNexus() method is:
5157 %
5158 %      MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5159 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5160 %
5161 %  A description of each parameter follows:
5162 %
5163 %    o image: the image.
5164 %
5165 %    o nexus_info: the cache nexus to sync.
5166 %
5167 %    o exception: return any errors or warnings in this structure.
5168 %
5169 */
5170 MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5171   NexusInfo *nexus_info,ExceptionInfo *exception)
5172 {
5173   CacheInfo
5174     *cache_info;
5175
5176   MagickBooleanType
5177     status;
5178
5179   /*
5180     Transfer pixels to the cache.
5181   */
5182   assert(image != (Image *) NULL);
5183   assert(image->signature == MagickSignature);
5184   if (image->cache == (Cache) NULL)
5185     ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5186   cache_info=(CacheInfo *) image->cache;
5187   assert(cache_info->signature == MagickSignature);
5188   if (cache_info->type == UndefinedCache)
5189     return(MagickFalse);
5190   if ((image->clip_mask != (Image *) NULL) &&
5191       (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5192     return(MagickFalse);
5193   if ((image->mask != (Image *) NULL) &&
5194       (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5195     return(MagickFalse);
5196   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5197     return(MagickTrue);
5198   assert(cache_info->signature == MagickSignature);
5199   status=WritePixelCachePixels(cache_info,nexus_info,exception);
5200   if ((cache_info->metacontent_extent != 0) &&
5201       (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5202     return(MagickFalse);
5203   return(status);
5204 }
5205 \f
5206 /*
5207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5208 %                                                                             %
5209 %                                                                             %
5210 %                                                                             %
5211 +   S y n c A u t h e n t i c P i x e l C a c h e                             %
5212 %                                                                             %
5213 %                                                                             %
5214 %                                                                             %
5215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5216 %
5217 %  SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5218 %  or disk cache.  The method returns MagickTrue if the pixel region is synced,
5219 %  otherwise MagickFalse.
5220 %
5221 %  The format of the SyncAuthenticPixelsCache() method is:
5222 %
5223 %      MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5224 %        ExceptionInfo *exception)
5225 %
5226 %  A description of each parameter follows:
5227 %
5228 %    o image: the image.
5229 %
5230 %    o exception: return any errors or warnings in this structure.
5231 %
5232 */
5233 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5234   ExceptionInfo *exception)
5235 {
5236   CacheInfo
5237     *cache_info;
5238
5239   const int
5240     id = GetOpenMPThreadId();
5241
5242   MagickBooleanType
5243     status;
5244
5245   assert(image != (Image *) NULL);
5246   assert(image->signature == MagickSignature);
5247   assert(image->cache != (Cache) NULL);
5248   cache_info=(CacheInfo *) image->cache;
5249   assert(cache_info->signature == MagickSignature);
5250   assert(id < (int) cache_info->number_threads);
5251   status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5252     exception);
5253   return(status);
5254 }
5255 \f
5256 /*
5257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5258 %                                                                             %
5259 %                                                                             %
5260 %                                                                             %
5261 %   S y n c A u t h e n t i c P i x e l s                                     %
5262 %                                                                             %
5263 %                                                                             %
5264 %                                                                             %
5265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5266 %
5267 %  SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5268 %  The method returns MagickTrue if the pixel region is flushed, otherwise
5269 %  MagickFalse.
5270 %
5271 %  The format of the SyncAuthenticPixels() method is:
5272 %
5273 %      MagickBooleanType SyncAuthenticPixels(Image *image,
5274 %        ExceptionInfo *exception)
5275 %
5276 %  A description of each parameter follows:
5277 %
5278 %    o image: the image.
5279 %
5280 %    o exception: return any errors or warnings in this structure.
5281 %
5282 */
5283 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5284   ExceptionInfo *exception)
5285 {
5286   CacheInfo
5287     *cache_info;
5288
5289   const int
5290     id = GetOpenMPThreadId();
5291
5292   MagickBooleanType
5293     status;
5294
5295   assert(image != (Image *) NULL);
5296   assert(image->signature == MagickSignature);
5297   assert(image->cache != (Cache) NULL);
5298   cache_info=(CacheInfo *) image->cache;
5299   assert(cache_info->signature == MagickSignature);
5300   if (cache_info->methods.sync_authentic_pixels_handler !=
5301        (SyncAuthenticPixelsHandler) NULL)
5302     {
5303       status=cache_info->methods.sync_authentic_pixels_handler(image,
5304         exception);
5305       return(status);
5306     }
5307   assert(id < (int) cache_info->number_threads);
5308   status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5309     exception);
5310   return(status);
5311 }
5312 \f
5313 /*
5314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5315 %                                                                             %
5316 %                                                                             %
5317 %                                                                             %
5318 +   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                       %
5319 %                                                                             %
5320 %                                                                             %
5321 %                                                                             %
5322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5323 %
5324 %  WritePixelCacheMetacontent() writes the meta-content to the specified region
5325 %  of the pixel cache.
5326 %
5327 %  The format of the WritePixelCacheMetacontent() method is:
5328 %
5329 %      MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5330 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5331 %
5332 %  A description of each parameter follows:
5333 %
5334 %    o cache_info: the pixel cache.
5335 %
5336 %    o nexus_info: the cache nexus to write the meta-content.
5337 %
5338 %    o exception: return any errors or warnings in this structure.
5339 %
5340 */
5341 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5342   NexusInfo *nexus_info,ExceptionInfo *exception)
5343 {
5344   MagickOffsetType
5345     count,
5346     offset;
5347
5348   MagickSizeType
5349     extent,
5350     length;
5351
5352   register const unsigned char
5353     *restrict p;
5354
5355   register ssize_t
5356     y;
5357
5358   size_t
5359     rows;
5360
5361   if (cache_info->metacontent_extent == 0)
5362     return(MagickFalse);
5363   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5364     return(MagickTrue);
5365   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5366     nexus_info->region.x;
5367   length=(MagickSizeType) nexus_info->region.width*
5368     cache_info->metacontent_extent;
5369   rows=nexus_info->region.height;
5370   extent=(MagickSizeType) length*rows;
5371   p=(unsigned char *) nexus_info->metacontent;
5372   switch (cache_info->type)
5373   {
5374     case MemoryCache:
5375     case MapCache:
5376     {
5377       register unsigned char
5378         *restrict q;
5379
5380       /*
5381         Write associated pixels to memory.
5382       */
5383       if ((cache_info->columns == nexus_info->region.width) &&
5384           (extent == (MagickSizeType) ((size_t) extent)))
5385         {
5386           length=extent;
5387           rows=1UL;
5388         }
5389       q=(unsigned char *) cache_info->metacontent+offset*
5390         cache_info->metacontent_extent;
5391       for (y=0; y < (ssize_t) rows; y++)
5392       {
5393         (void) memcpy(q,p,(size_t) length);
5394         p+=nexus_info->region.width*cache_info->metacontent_extent;
5395         q+=cache_info->columns*cache_info->metacontent_extent;
5396       }
5397       break;
5398     }
5399     case DiskCache:
5400     {
5401       /*
5402         Write associated pixels to disk.
5403       */
5404       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5405         {
5406           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5407             cache_info->cache_filename);
5408           return(MagickFalse);
5409         }
5410       if ((cache_info->columns == nexus_info->region.width) &&
5411           (extent <= MagickMaxBufferExtent))
5412         {
5413           length=extent;
5414           rows=1UL;
5415         }
5416       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5417       for (y=0; y < (ssize_t) rows; y++)
5418       {
5419         count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5420           cache_info->number_channels*sizeof(Quantum)+offset*
5421           cache_info->metacontent_extent,length,(const unsigned char *) p);
5422         if ((MagickSizeType) count != length)
5423           break;
5424         p+=nexus_info->region.width*cache_info->metacontent_extent;
5425         offset+=cache_info->columns;
5426       }
5427       if (y < (ssize_t) rows)
5428         {
5429           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5430             cache_info->cache_filename);
5431           return(MagickFalse);
5432         }
5433       break;
5434     }
5435     default:
5436       break;
5437   }
5438   if ((cache_info->debug != MagickFalse) &&
5439       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5440     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5441       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5442       nexus_info->region.width,(double) nexus_info->region.height,(double)
5443       nexus_info->region.x,(double) nexus_info->region.y);
5444   return(MagickTrue);
5445 }
5446 \f
5447 /*
5448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5449 %                                                                             %
5450 %                                                                             %
5451 %                                                                             %
5452 +   W r i t e C a c h e P i x e l s                                           %
5453 %                                                                             %
5454 %                                                                             %
5455 %                                                                             %
5456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5457 %
5458 %  WritePixelCachePixels() writes image pixels to the specified region of the
5459 %  pixel cache.
5460 %
5461 %  The format of the WritePixelCachePixels() method is:
5462 %
5463 %      MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5464 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5465 %
5466 %  A description of each parameter follows:
5467 %
5468 %    o cache_info: the pixel cache.
5469 %
5470 %    o nexus_info: the cache nexus to write the pixels.
5471 %
5472 %    o exception: return any errors or warnings in this structure.
5473 %
5474 */
5475 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5476   NexusInfo *nexus_info,ExceptionInfo *exception)
5477 {
5478   MagickOffsetType
5479     count,
5480     offset;
5481
5482   MagickSizeType
5483     extent,
5484     length;
5485
5486   register const Quantum
5487     *restrict p;
5488
5489   register ssize_t
5490     y;
5491
5492   size_t
5493     rows;
5494
5495   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5496     return(MagickTrue);
5497   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5498     nexus_info->region.x;
5499   length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5500     sizeof(Quantum);
5501   rows=nexus_info->region.height;
5502   extent=length*rows;
5503   p=nexus_info->pixels;
5504   switch (cache_info->type)
5505   {
5506     case MemoryCache:
5507     case MapCache:
5508     {
5509       register Quantum
5510         *restrict q;
5511
5512       /*
5513         Write pixels to memory.
5514       */
5515       if ((cache_info->columns == nexus_info->region.width) &&
5516           (extent == (MagickSizeType) ((size_t) extent)))
5517         {
5518           length=extent;
5519           rows=1UL;
5520         }
5521       q=cache_info->pixels+offset*cache_info->number_channels;
5522       for (y=0; y < (ssize_t) rows; y++)
5523       {
5524         (void) memcpy(q,p,(size_t) length);
5525         p+=nexus_info->region.width*cache_info->number_channels;
5526         q+=cache_info->columns*cache_info->number_channels;
5527       }
5528       break;
5529     }
5530     case DiskCache:
5531     {
5532       /*
5533         Write pixels to disk.
5534       */
5535       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5536         {
5537           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5538             cache_info->cache_filename);
5539           return(MagickFalse);
5540         }
5541       if ((cache_info->columns == nexus_info->region.width) &&
5542           (extent <= MagickMaxBufferExtent))
5543         {
5544           length=extent;
5545           rows=1UL;
5546         }
5547       for (y=0; y < (ssize_t) rows; y++)
5548       {
5549         count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5550           cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5551           p);
5552         if ((MagickSizeType) count != length)
5553           break;
5554         p+=nexus_info->region.width*cache_info->number_channels;
5555         offset+=cache_info->columns;
5556       }
5557       if (y < (ssize_t) rows)
5558         {
5559           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5560             cache_info->cache_filename);
5561           return(MagickFalse);
5562         }
5563       break;
5564     }
5565     default:
5566       break;
5567   }
5568   if ((cache_info->debug != MagickFalse) &&
5569       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5570     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5571       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5572       nexus_info->region.width,(double) nexus_info->region.height,(double)
5573       nexus_info->region.x,(double) nexus_info->region.y);
5574   return(MagickTrue);
5575 }