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