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