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