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