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