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