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