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