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