]> 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   size_t
3734     columns,
3735     packet_size;
3736
3737   assert(image != (const Image *) NULL);
3738   assert(image->signature == MagickSignature);
3739   assert(image->cache != (Cache) NULL);
3740   if (image->debug != MagickFalse)
3741     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3742   if ((image->columns == 0) || (image->rows == 0))
3743     ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3744   cache_info=(CacheInfo *) image->cache;
3745   assert(cache_info->signature == MagickSignature);
3746   source_info=(*cache_info);
3747   source_info.file=(-1);
3748   (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3749     image->filename,(double) GetImageIndexInList(image));
3750   cache_info->storage_class=image->storage_class;
3751   cache_info->colorspace=image->colorspace;
3752   cache_info->matte=image->matte;
3753   cache_info->mask=image->mask;
3754   cache_info->rows=image->rows;
3755   cache_info->columns=image->columns;
3756   InitializePixelChannelMap(image);
3757   cache_info->number_channels=GetPixelChannels(image);
3758   (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3759     sizeof(*image->channel_map));
3760   cache_info->metacontent_extent=image->metacontent_extent;
3761   cache_info->mode=mode;
3762   if (image->ping != MagickFalse)
3763     {
3764       cache_info->type=PingCache;
3765       cache_info->pixels=(Quantum *) NULL;
3766       cache_info->metacontent=(void *) NULL;
3767       cache_info->length=0;
3768       return(MagickTrue);
3769     }
3770   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3771   packet_size=cache_info->number_channels*sizeof(Quantum);
3772   if (image->metacontent_extent != 0)
3773     packet_size+=cache_info->metacontent_extent;
3774   length=number_pixels*packet_size;
3775   columns=(size_t) (length/cache_info->rows/packet_size);
3776   if (cache_info->columns != columns)
3777     ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3778       image->filename);
3779   cache_info->length=length;
3780   status=AcquireMagickResource(AreaResource,cache_info->length);
3781   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3782     cache_info->metacontent_extent);
3783   if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3784     {
3785       status=AcquireMagickResource(MemoryResource,cache_info->length);
3786       if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3787           (cache_info->type == MemoryCache))
3788         {
3789           AllocatePixelCachePixels(cache_info);
3790           if (cache_info->pixels == (Quantum *) NULL)
3791             cache_info->pixels=source_info.pixels;
3792           else
3793             {
3794               /*
3795                 Create memory pixel cache.
3796               */
3797               status=MagickTrue;
3798               if (image->debug != MagickFalse)
3799                 {
3800                   (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3801                   (void) FormatLocaleString(message,MaxTextExtent,
3802                     "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3803                     cache_info->filename,cache_info->mapped != MagickFalse ?
3804                     "anonymous" : "heap",(double) cache_info->columns,(double)
3805                     cache_info->rows,(double) cache_info->number_channels,
3806                     format);
3807                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3808                     message);
3809                 }
3810               cache_info->type=MemoryCache;
3811               cache_info->metacontent=(void *) NULL;
3812               if (cache_info->metacontent_extent != 0)
3813                 cache_info->metacontent=(void *) (cache_info->pixels+
3814                   number_pixels*cache_info->number_channels);
3815               if ((source_info.storage_class != UndefinedClass) &&
3816                   (mode != ReadMode))
3817                 {
3818                   status=ClonePixelCachePixels(cache_info,&source_info,
3819                     exception);
3820                   RelinquishPixelCachePixels(&source_info);
3821                 }
3822               return(status);
3823             }
3824         }
3825       RelinquishMagickResource(MemoryResource,cache_info->length);
3826     }
3827   /*
3828     Create pixel cache on disk.
3829   */
3830   status=AcquireMagickResource(DiskResource,cache_info->length);
3831   if (status == MagickFalse)
3832     {
3833       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3834         "CacheResourcesExhausted","`%s'",image->filename);
3835       return(MagickFalse);
3836     }
3837   if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3838     {
3839       (void) ClosePixelCacheOnDisk(cache_info);
3840       *cache_info->cache_filename='\0';
3841     }
3842   if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3843     {
3844       RelinquishMagickResource(DiskResource,cache_info->length);
3845       ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3846         image->filename);
3847       return(MagickFalse);
3848     }
3849   status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3850     cache_info->length);
3851   if (status == MagickFalse)
3852     {
3853       ThrowFileException(exception,CacheError,"UnableToExtendCache",
3854         image->filename);
3855       return(MagickFalse);
3856     }
3857   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3858     cache_info->metacontent_extent);
3859   if (length != (MagickSizeType) ((size_t) length))
3860     cache_info->type=DiskCache;
3861   else
3862     {
3863       status=AcquireMagickResource(MapResource,cache_info->length);
3864       if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3865           (cache_info->type != MemoryCache))
3866         cache_info->type=DiskCache;
3867       else
3868         {
3869           cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3870             cache_info->offset,(size_t) cache_info->length);
3871           if (cache_info->pixels == (Quantum *) NULL)
3872             {
3873               cache_info->type=DiskCache;
3874               cache_info->pixels=source_info.pixels;
3875             }
3876           else
3877             {
3878               /*
3879                 Create file-backed memory-mapped pixel cache.
3880               */
3881               status=MagickTrue;
3882               (void) ClosePixelCacheOnDisk(cache_info);
3883               cache_info->type=MapCache;
3884               cache_info->mapped=MagickTrue;
3885               cache_info->metacontent=(void *) NULL;
3886               if (cache_info->metacontent_extent != 0)
3887                 cache_info->metacontent=(void *) (cache_info->pixels+
3888                   number_pixels*cache_info->number_channels);
3889               if ((source_info.storage_class != UndefinedClass) &&
3890                   (mode != ReadMode))
3891                 {
3892                   status=ClonePixelCachePixels(cache_info,&source_info,
3893                     exception);
3894                   RelinquishPixelCachePixels(&source_info);
3895                 }
3896               if (image->debug != MagickFalse)
3897                 {
3898                   (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3899                   (void) FormatLocaleString(message,MaxTextExtent,
3900                     "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
3901                     cache_info->filename,cache_info->cache_filename,
3902                     cache_info->file,(double) cache_info->columns,(double)
3903                     cache_info->rows,(double) cache_info->number_channels,
3904                     format);
3905                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3906                     message);
3907                 }
3908               return(status);
3909             }
3910         }
3911       RelinquishMagickResource(MapResource,cache_info->length);
3912     }
3913   status=MagickTrue;
3914   if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3915     {
3916       status=ClonePixelCachePixels(cache_info,&source_info,exception);
3917       RelinquishPixelCachePixels(&source_info);
3918     }
3919   if (image->debug != MagickFalse)
3920     {
3921       (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3922       (void) FormatLocaleString(message,MaxTextExtent,
3923         "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
3924         cache_info->cache_filename,cache_info->file,(double)
3925         cache_info->columns,(double) cache_info->rows,(double)
3926         cache_info->number_channels,format);
3927       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3928     }
3929   return(status);
3930 }
3931 \f
3932 /*
3933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3934 %                                                                             %
3935 %                                                                             %
3936 %                                                                             %
3937 +   P e r s i s t P i x e l C a c h e                                         %
3938 %                                                                             %
3939 %                                                                             %
3940 %                                                                             %
3941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3942 %
3943 %  PersistPixelCache() attaches to or initializes a persistent pixel cache.  A
3944 %  persistent pixel cache is one that resides on disk and is not destroyed
3945 %  when the program exits.
3946 %
3947 %  The format of the PersistPixelCache() method is:
3948 %
3949 %      MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3950 %        const MagickBooleanType attach,MagickOffsetType *offset,
3951 %        ExceptionInfo *exception)
3952 %
3953 %  A description of each parameter follows:
3954 %
3955 %    o image: the image.
3956 %
3957 %    o filename: the persistent pixel cache filename.
3958 %
3959 %    o attach: A value other than zero initializes the persistent pixel cache.
3960 %
3961 %    o initialize: A value other than zero initializes the persistent pixel
3962 %      cache.
3963 %
3964 %    o offset: the offset in the persistent cache to store pixels.
3965 %
3966 %    o exception: return any errors or warnings in this structure.
3967 %
3968 */
3969 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3970   const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3971   ExceptionInfo *exception)
3972 {
3973   CacheInfo
3974     *cache_info,
3975     *clone_info;
3976
3977   Image
3978     clone_image;
3979
3980   MagickBooleanType
3981     status;
3982
3983   ssize_t
3984     page_size;
3985
3986   assert(image != (Image *) NULL);
3987   assert(image->signature == MagickSignature);
3988   if (image->debug != MagickFalse)
3989     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3990   assert(image->cache != (void *) NULL);
3991   assert(filename != (const char *) NULL);
3992   assert(offset != (MagickOffsetType *) NULL);
3993   page_size=GetMagickPageSize();
3994   cache_info=(CacheInfo *) image->cache;
3995   assert(cache_info->signature == MagickSignature);
3996   if (attach != MagickFalse)
3997     {
3998       /*
3999         Attach existing persistent pixel cache.
4000       */
4001       if (image->debug != MagickFalse)
4002         (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4003           "attach persistent cache");
4004       (void) CopyMagickString(cache_info->cache_filename,filename,
4005         MaxTextExtent);
4006       cache_info->type=DiskCache;
4007       cache_info->offset=(*offset);
4008       if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4009         return(MagickFalse);
4010       *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4011       return(MagickTrue);
4012     }
4013   if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4014       (cache_info->reference_count == 1))
4015     {
4016       LockSemaphoreInfo(cache_info->semaphore);
4017       if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4018           (cache_info->reference_count == 1))
4019         {
4020           int
4021             status;
4022
4023           /*
4024             Usurp existing persistent pixel cache.
4025           */
4026           status=rename_utf8(cache_info->cache_filename,filename);
4027           if (status == 0)
4028             {
4029               (void) CopyMagickString(cache_info->cache_filename,filename,
4030                 MaxTextExtent);
4031               *offset+=cache_info->length+page_size-(cache_info->length %
4032                 page_size);
4033               UnlockSemaphoreInfo(cache_info->semaphore);
4034               cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4035               if (image->debug != MagickFalse)
4036                 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4037                   "Usurp resident persistent cache");
4038               return(MagickTrue);
4039             }
4040         }
4041       UnlockSemaphoreInfo(cache_info->semaphore);
4042     }
4043   /*
4044     Clone persistent pixel cache.
4045   */
4046   clone_image=(*image);
4047   clone_info=(CacheInfo *) clone_image.cache;
4048   image->cache=ClonePixelCache(cache_info);
4049   cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4050   (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4051   cache_info->type=DiskCache;
4052   cache_info->offset=(*offset);
4053   cache_info=(CacheInfo *) image->cache;
4054   status=OpenPixelCache(image,IOMode,exception);
4055   if (status != MagickFalse)
4056     status=ClonePixelCachePixels(cache_info,clone_info,exception);
4057   *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4058   clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4059   return(status);
4060 }
4061 \f
4062 /*
4063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4064 %                                                                             %
4065 %                                                                             %
4066 %                                                                             %
4067 +   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                 %
4068 %                                                                             %
4069 %                                                                             %
4070 %                                                                             %
4071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4072 %
4073 %  QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4074 %  defined by the region rectangle and returns a pointer to the region.  This
4075 %  region is subsequently transferred from the pixel cache with
4076 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4077 %  pixels are transferred, otherwise a NULL is returned.
4078 %
4079 %  The format of the QueueAuthenticPixelCacheNexus() method is:
4080 %
4081 %      Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4082 %        const ssize_t y,const size_t columns,const size_t rows,
4083 %        const MagickBooleanType clone,NexusInfo *nexus_info,
4084 %        ExceptionInfo *exception)
4085 %
4086 %  A description of each parameter follows:
4087 %
4088 %    o image: the image.
4089 %
4090 %    o x,y,columns,rows:  These values define the perimeter of a region of
4091 %      pixels.
4092 %
4093 %    o nexus_info: the cache nexus to set.
4094 %
4095 %    o clone: clone the pixel cache.
4096 %
4097 %    o exception: return any errors or warnings in this structure.
4098 %
4099 */
4100 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4101   const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4102   const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4103 {
4104   CacheInfo
4105     *cache_info;
4106
4107   MagickOffsetType
4108     offset;
4109
4110   MagickSizeType
4111     number_pixels;
4112
4113   RectangleInfo
4114     region;
4115
4116   /*
4117     Validate pixel cache geometry.
4118   */
4119   assert(image != (const Image *) NULL);
4120   assert(image->signature == MagickSignature);
4121   assert(image->cache != (Cache) NULL);
4122   cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4123   if (cache_info == (Cache) NULL)
4124     return((Quantum *) NULL);
4125   assert(cache_info->signature == MagickSignature);
4126   if ((cache_info->columns == 0) && (cache_info->rows == 0))
4127     {
4128       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4129         "NoPixelsDefinedInCache","`%s'",image->filename);
4130       return((Quantum *) NULL);
4131     }
4132   if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4133       (y >= (ssize_t) cache_info->rows))
4134     {
4135       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4136         "PixelsAreNotAuthentic","`%s'",image->filename);
4137       return((Quantum *) NULL);
4138     }
4139   offset=(MagickOffsetType) y*cache_info->columns+x;
4140   if (offset < 0)
4141     return((Quantum *) NULL);
4142   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4143   offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4144   if ((MagickSizeType) offset >= number_pixels)
4145     return((Quantum *) NULL);
4146   /*
4147     Return pixel cache.
4148   */
4149   region.x=x;
4150   region.y=y;
4151   region.width=columns;
4152   region.height=rows;
4153   return(SetPixelCacheNexusPixels(image,&region,nexus_info,exception));
4154 }
4155 \f
4156 /*
4157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4158 %                                                                             %
4159 %                                                                             %
4160 %                                                                             %
4161 +   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                         %
4162 %                                                                             %
4163 %                                                                             %
4164 %                                                                             %
4165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4166 %
4167 %  QueueAuthenticPixelsCache() allocates an region to store image pixels as
4168 %  defined by the region rectangle and returns a pointer to the region.  This
4169 %  region is subsequently transferred from the pixel cache with
4170 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4171 %  pixels are transferred, otherwise a NULL is returned.
4172 %
4173 %  The format of the QueueAuthenticPixelsCache() method is:
4174 %
4175 %      Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4176 %        const ssize_t y,const size_t columns,const size_t rows,
4177 %        ExceptionInfo *exception)
4178 %
4179 %  A description of each parameter follows:
4180 %
4181 %    o image: the image.
4182 %
4183 %    o x,y,columns,rows:  These values define the perimeter of a region of
4184 %      pixels.
4185 %
4186 %    o exception: return any errors or warnings in this structure.
4187 %
4188 */
4189 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4190   const ssize_t y,const size_t columns,const size_t rows,
4191   ExceptionInfo *exception)
4192 {
4193   CacheInfo
4194     *cache_info;
4195
4196   const int
4197     id = GetOpenMPThreadId();
4198
4199   Quantum
4200     *q;
4201
4202   assert(image != (const Image *) NULL);
4203   assert(image->signature == MagickSignature);
4204   assert(image->cache != (Cache) NULL);
4205   cache_info=(CacheInfo *) image->cache;
4206   assert(cache_info->signature == MagickSignature);
4207   assert(id < (int) cache_info->number_threads);
4208   q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4209     cache_info->nexus_info[id],exception);
4210   return(q);
4211 }
4212 \f
4213 /*
4214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4215 %                                                                             %
4216 %                                                                             %
4217 %                                                                             %
4218 %   Q u e u e A u t h e n t i c P i x e l s                                   %
4219 %                                                                             %
4220 %                                                                             %
4221 %                                                                             %
4222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4223 %
4224 %  QueueAuthenticPixels() queues a mutable pixel region.  If the region is
4225 %  successfully initialized a pointer to a Quantum array representing the
4226 %  region is returned, otherwise NULL is returned.  The returned pointer may
4227 %  point to a temporary working buffer for the pixels or it may point to the
4228 %  final location of the pixels in memory.
4229 %
4230 %  Write-only access means that any existing pixel values corresponding to
4231 %  the region are ignored.  This is useful if the initial image is being
4232 %  created from scratch, or if the existing pixel values are to be
4233 %  completely replaced without need to refer to their pre-existing values.
4234 %  The application is free to read and write the pixel buffer returned by
4235 %  QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4236 %  initialize the pixel array values. Initializing pixel array values is the
4237 %  application's responsibility.
4238 %
4239 %  Performance is maximized if the selected region is part of one row, or
4240 %  one or more full rows, since then there is opportunity to access the
4241 %  pixels in-place (without a copy) if the image is in memory, or in a
4242 %  memory-mapped file. The returned pointer must *never* be deallocated
4243 %  by the user.
4244 %
4245 %  Pixels accessed via the returned pointer represent a simple array of type
4246 %  Quantum. If the image type is CMYK or the storage class is PseudoClass,
4247 %  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4248 %  obtain the meta-content (of type void) corresponding to the region.
4249 %  Once the Quantum (and/or Quantum) array has been updated, the
4250 %  changes must be saved back to the underlying image using
4251 %  SyncAuthenticPixels() or they may be lost.
4252 %
4253 %  The format of the QueueAuthenticPixels() method is:
4254 %
4255 %      Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4256 %        const ssize_t y,const size_t columns,const size_t rows,
4257 %        ExceptionInfo *exception)
4258 %
4259 %  A description of each parameter follows:
4260 %
4261 %    o image: the image.
4262 %
4263 %    o x,y,columns,rows:  These values define the perimeter of a region of
4264 %      pixels.
4265 %
4266 %    o exception: return any errors or warnings in this structure.
4267 %
4268 */
4269 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4270   const ssize_t y,const size_t columns,const size_t rows,
4271   ExceptionInfo *exception)
4272 {
4273   CacheInfo
4274     *cache_info;
4275
4276   const int
4277     id = GetOpenMPThreadId();
4278
4279   Quantum
4280     *q;
4281
4282   assert(image != (Image *) NULL);
4283   assert(image->signature == MagickSignature);
4284   assert(image->cache != (Cache) NULL);
4285   cache_info=(CacheInfo *) image->cache;
4286   assert(cache_info->signature == MagickSignature);
4287   if (cache_info->methods.queue_authentic_pixels_handler !=
4288       (QueueAuthenticPixelsHandler) NULL)
4289     {
4290       q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4291         rows,exception);
4292       return(q);
4293     }
4294   assert(id < (int) cache_info->number_threads);
4295   q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4296     cache_info->nexus_info[id],exception);
4297   return(q);
4298 }
4299 \f
4300 /*
4301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4302 %                                                                             %
4303 %                                                                             %
4304 %                                                                             %
4305 +   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                         %
4306 %                                                                             %
4307 %                                                                             %
4308 %                                                                             %
4309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4310 %
4311 %  ReadPixelCacheMetacontent() reads metacontent from the specified region of
4312 %  the pixel cache.
4313 %
4314 %  The format of the ReadPixelCacheMetacontent() method is:
4315 %
4316 %      MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4317 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4318 %
4319 %  A description of each parameter follows:
4320 %
4321 %    o cache_info: the pixel cache.
4322 %
4323 %    o nexus_info: the cache nexus to read the metacontent.
4324 %
4325 %    o exception: return any errors or warnings in this structure.
4326 %
4327 */
4328 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4329   NexusInfo *nexus_info,ExceptionInfo *exception)
4330 {
4331   MagickOffsetType
4332     count,
4333     offset;
4334
4335   MagickSizeType
4336     extent,
4337     length;
4338
4339   register ssize_t
4340     y;
4341
4342   register unsigned char
4343     *restrict q;
4344
4345   size_t
4346     rows;
4347
4348   if (cache_info->metacontent_extent == 0)
4349     return(MagickFalse);
4350   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4351     return(MagickTrue);
4352   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4353     nexus_info->region.x;
4354   length=(MagickSizeType) nexus_info->region.width*
4355     cache_info->metacontent_extent;
4356   rows=nexus_info->region.height;
4357   extent=length*rows;
4358   q=(unsigned char *) nexus_info->metacontent;
4359   switch (cache_info->type)
4360   {
4361     case MemoryCache:
4362     case MapCache:
4363     {
4364       register unsigned char
4365         *restrict p;
4366
4367       /*
4368         Read meta-content from memory.
4369       */
4370       if ((cache_info->columns == nexus_info->region.width) &&
4371           (extent == (MagickSizeType) ((size_t) extent)))
4372         {
4373           length=extent;
4374           rows=1UL;
4375         }
4376       p=(unsigned char *) cache_info->metacontent+offset*
4377         cache_info->metacontent_extent;
4378       for (y=0; y < (ssize_t) rows; y++)
4379       {
4380         (void) memcpy(q,p,(size_t) length);
4381         p+=cache_info->metacontent_extent*cache_info->columns;
4382         q+=cache_info->metacontent_extent*nexus_info->region.width;
4383       }
4384       break;
4385     }
4386     case DiskCache:
4387     {
4388       /*
4389         Read meta content from disk.
4390       */
4391       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4392         {
4393           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4394             cache_info->cache_filename);
4395           return(MagickFalse);
4396         }
4397       if ((cache_info->columns == nexus_info->region.width) &&
4398           (extent <= MagickMaxBufferExtent))
4399         {
4400           length=extent;
4401           rows=1UL;
4402         }
4403       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4404       for (y=0; y < (ssize_t) rows; y++)
4405       {
4406         count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4407           cache_info->number_channels*sizeof(Quantum)+offset*
4408           cache_info->metacontent_extent,length,(unsigned char *) q);
4409         if ((MagickSizeType) count != length)
4410           break;
4411         offset+=cache_info->columns;
4412         q+=cache_info->metacontent_extent*nexus_info->region.width;
4413       }
4414       if (IsFileDescriptorLimitExceeded() != MagickFalse)
4415         (void) ClosePixelCacheOnDisk(cache_info);
4416       if (y < (ssize_t) rows)
4417         {
4418           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4419             cache_info->cache_filename);
4420           return(MagickFalse);
4421         }
4422       break;
4423     }
4424     default:
4425       break;
4426   }
4427   if ((cache_info->debug != MagickFalse) &&
4428       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4429     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4430       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4431       nexus_info->region.width,(double) nexus_info->region.height,(double)
4432       nexus_info->region.x,(double) nexus_info->region.y);
4433   return(MagickTrue);
4434 }
4435 \f
4436 /*
4437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4438 %                                                                             %
4439 %                                                                             %
4440 %                                                                             %
4441 +   R e a d P i x e l C a c h e P i x e l s                                   %
4442 %                                                                             %
4443 %                                                                             %
4444 %                                                                             %
4445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4446 %
4447 %  ReadPixelCachePixels() reads pixels from the specified region of the pixel
4448 %  cache.
4449 %
4450 %  The format of the ReadPixelCachePixels() method is:
4451 %
4452 %      MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4453 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4454 %
4455 %  A description of each parameter follows:
4456 %
4457 %    o cache_info: the pixel cache.
4458 %
4459 %    o nexus_info: the cache nexus to read the pixels.
4460 %
4461 %    o exception: return any errors or warnings in this structure.
4462 %
4463 */
4464 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4465   NexusInfo *nexus_info,ExceptionInfo *exception)
4466 {
4467   MagickOffsetType
4468     count,
4469     offset;
4470
4471   MagickSizeType
4472     extent,
4473     length;
4474
4475   register Quantum
4476     *restrict q;
4477
4478   register ssize_t
4479     y;
4480
4481   size_t
4482     rows;
4483
4484   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4485     return(MagickTrue);
4486   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4487     nexus_info->region.x;
4488   length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4489     sizeof(Quantum);
4490   rows=nexus_info->region.height;
4491   extent=length*rows;
4492   q=nexus_info->pixels;
4493   switch (cache_info->type)
4494   {
4495     case MemoryCache:
4496     case MapCache:
4497     {
4498       register Quantum
4499         *restrict p;
4500
4501       /*
4502         Read pixels from memory.
4503       */
4504       if ((cache_info->columns == nexus_info->region.width) &&
4505           (extent == (MagickSizeType) ((size_t) extent)))
4506         {
4507           length=extent;
4508           rows=1UL;
4509         }
4510       p=cache_info->pixels+offset*cache_info->number_channels;
4511       for (y=0; y < (ssize_t) rows; y++)
4512       {
4513         (void) memcpy(q,p,(size_t) length);
4514         p+=cache_info->number_channels*cache_info->columns;
4515         q+=cache_info->number_channels*nexus_info->region.width;
4516       }
4517       break;
4518     }
4519     case DiskCache:
4520     {
4521       /*
4522         Read pixels from disk.
4523       */
4524       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4525         {
4526           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4527             cache_info->cache_filename);
4528           return(MagickFalse);
4529         }
4530       if ((cache_info->columns == nexus_info->region.width) &&
4531           (extent <= MagickMaxBufferExtent))
4532         {
4533           length=extent;
4534           rows=1UL;
4535         }
4536       for (y=0; y < (ssize_t) rows; y++)
4537       {
4538         count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4539           cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4540         if ((MagickSizeType) count != length)
4541           break;
4542         offset+=cache_info->columns;
4543         q+=cache_info->number_channels*nexus_info->region.width;
4544       }
4545       if (IsFileDescriptorLimitExceeded() != MagickFalse)
4546         (void) ClosePixelCacheOnDisk(cache_info);
4547       if (y < (ssize_t) rows)
4548         {
4549           ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4550             cache_info->cache_filename);
4551           return(MagickFalse);
4552         }
4553       break;
4554     }
4555     default:
4556       break;
4557   }
4558   if ((cache_info->debug != MagickFalse) &&
4559       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4560     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4561       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4562       nexus_info->region.width,(double) nexus_info->region.height,(double)
4563       nexus_info->region.x,(double) nexus_info->region.y);
4564   return(MagickTrue);
4565 }
4566 \f
4567 /*
4568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4569 %                                                                             %
4570 %                                                                             %
4571 %                                                                             %
4572 +   R e f e r e n c e P i x e l C a c h e                                     %
4573 %                                                                             %
4574 %                                                                             %
4575 %                                                                             %
4576 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4577 %
4578 %  ReferencePixelCache() increments the reference count associated with the
4579 %  pixel cache returning a pointer to the cache.
4580 %
4581 %  The format of the ReferencePixelCache method is:
4582 %
4583 %      Cache ReferencePixelCache(Cache cache_info)
4584 %
4585 %  A description of each parameter follows:
4586 %
4587 %    o cache_info: the pixel cache.
4588 %
4589 */
4590 MagickPrivate Cache ReferencePixelCache(Cache cache)
4591 {
4592   CacheInfo
4593     *cache_info;
4594
4595   assert(cache != (Cache *) NULL);
4596   cache_info=(CacheInfo *) cache;
4597   assert(cache_info->signature == MagickSignature);
4598   LockSemaphoreInfo(cache_info->semaphore);
4599   cache_info->reference_count++;
4600   UnlockSemaphoreInfo(cache_info->semaphore);
4601   return(cache_info);
4602 }
4603 \f
4604 /*
4605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4606 %                                                                             %
4607 %                                                                             %
4608 %                                                                             %
4609 +   S e t P i x e l C a c h e M e t h o d s                                   %
4610 %                                                                             %
4611 %                                                                             %
4612 %                                                                             %
4613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4614 %
4615 %  SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4616 %
4617 %  The format of the SetPixelCacheMethods() method is:
4618 %
4619 %      SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4620 %
4621 %  A description of each parameter follows:
4622 %
4623 %    o cache: the pixel cache.
4624 %
4625 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
4626 %
4627 */
4628 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4629 {
4630   CacheInfo
4631     *cache_info;
4632
4633   GetOneAuthenticPixelFromHandler
4634     get_one_authentic_pixel_from_handler;
4635
4636   GetOneVirtualPixelFromHandler
4637     get_one_virtual_pixel_from_handler;
4638
4639   /*
4640     Set cache pixel methods.
4641   */
4642   assert(cache != (Cache) NULL);
4643   assert(cache_methods != (CacheMethods *) NULL);
4644   cache_info=(CacheInfo *) cache;
4645   assert(cache_info->signature == MagickSignature);
4646   if (cache_info->debug != MagickFalse)
4647     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4648       cache_info->filename);
4649   if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4650     cache_info->methods.get_virtual_pixel_handler=
4651       cache_methods->get_virtual_pixel_handler;
4652   if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4653     cache_info->methods.destroy_pixel_handler=
4654       cache_methods->destroy_pixel_handler;
4655   if (cache_methods->get_virtual_metacontent_from_handler !=
4656       (GetVirtualMetacontentFromHandler) NULL)
4657     cache_info->methods.get_virtual_metacontent_from_handler=
4658       cache_methods->get_virtual_metacontent_from_handler;
4659   if (cache_methods->get_authentic_pixels_handler !=
4660       (GetAuthenticPixelsHandler) NULL)
4661     cache_info->methods.get_authentic_pixels_handler=
4662       cache_methods->get_authentic_pixels_handler;
4663   if (cache_methods->queue_authentic_pixels_handler !=
4664       (QueueAuthenticPixelsHandler) NULL)
4665     cache_info->methods.queue_authentic_pixels_handler=
4666       cache_methods->queue_authentic_pixels_handler;
4667   if (cache_methods->sync_authentic_pixels_handler !=
4668       (SyncAuthenticPixelsHandler) NULL)
4669     cache_info->methods.sync_authentic_pixels_handler=
4670       cache_methods->sync_authentic_pixels_handler;
4671   if (cache_methods->get_authentic_pixels_from_handler !=
4672       (GetAuthenticPixelsFromHandler) NULL)
4673     cache_info->methods.get_authentic_pixels_from_handler=
4674       cache_methods->get_authentic_pixels_from_handler;
4675   if (cache_methods->get_authentic_metacontent_from_handler !=
4676       (GetAuthenticMetacontentFromHandler) NULL)
4677     cache_info->methods.get_authentic_metacontent_from_handler=
4678       cache_methods->get_authentic_metacontent_from_handler;
4679   get_one_virtual_pixel_from_handler=
4680     cache_info->methods.get_one_virtual_pixel_from_handler;
4681   if (get_one_virtual_pixel_from_handler !=
4682       (GetOneVirtualPixelFromHandler) NULL)
4683     cache_info->methods.get_one_virtual_pixel_from_handler=
4684       cache_methods->get_one_virtual_pixel_from_handler;
4685   get_one_authentic_pixel_from_handler=
4686     cache_methods->get_one_authentic_pixel_from_handler;
4687   if (get_one_authentic_pixel_from_handler !=
4688       (GetOneAuthenticPixelFromHandler) NULL)
4689     cache_info->methods.get_one_authentic_pixel_from_handler=
4690       cache_methods->get_one_authentic_pixel_from_handler;
4691 }
4692 \f
4693 /*
4694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4695 %                                                                             %
4696 %                                                                             %
4697 %                                                                             %
4698 +   S e t P i x e l C a c h e N e x u s P i x e l s                           %
4699 %                                                                             %
4700 %                                                                             %
4701 %                                                                             %
4702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703 %
4704 %  SetPixelCacheNexusPixels() defines the region of the cache for the
4705 %  specified cache nexus.
4706 %
4707 %  The format of the SetPixelCacheNexusPixels() method is:
4708 %
4709 %      Quantum SetPixelCacheNexusPixels(const Image *image,
4710 %        const RectangleInfo *region,NexusInfo *nexus_info,
4711 %        ExceptionInfo *exception)
4712 %
4713 %  A description of each parameter follows:
4714 %
4715 %    o image: the image.
4716 %
4717 %    o region: A pointer to the RectangleInfo structure that defines the
4718 %      region of this particular cache nexus.
4719 %
4720 %    o nexus_info: the cache nexus to set.
4721 %
4722 %    o exception: return any errors or warnings in this structure.
4723 %
4724 */
4725
4726 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4727   NexusInfo *nexus_info,ExceptionInfo *exception)
4728 {
4729   if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4730     return(MagickFalse);
4731   nexus_info->mapped=MagickFalse;
4732   nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
4733     nexus_info->length);
4734   if (nexus_info->cache == (Quantum *) NULL)
4735     {
4736       nexus_info->mapped=MagickTrue;
4737       nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4738         nexus_info->length);
4739     }
4740   if (nexus_info->cache == (Quantum *) NULL)
4741     {
4742       (void) ThrowMagickException(exception,GetMagickModule(),
4743         ResourceLimitError,"MemoryAllocationFailed","`%s'",
4744         cache_info->filename);
4745       return(MagickFalse);
4746     }
4747   return(MagickTrue);
4748 }
4749
4750 static Quantum *SetPixelCacheNexusPixels(const Image *image,
4751   const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4752 {
4753   CacheInfo
4754     *cache_info;
4755
4756   MagickBooleanType
4757     status;
4758
4759   MagickSizeType
4760     length,
4761     number_pixels;
4762
4763   cache_info=(CacheInfo *) image->cache;
4764   assert(cache_info->signature == MagickSignature);
4765   if (cache_info->type == UndefinedCache)
4766     return((Quantum *) NULL);
4767   nexus_info->region=(*region);
4768   if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
4769     {
4770       ssize_t
4771         x,
4772         y;
4773
4774       x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4775       y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4776       if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4777            (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4778           ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4779            ((nexus_info->region.width == cache_info->columns) ||
4780             ((nexus_info->region.width % cache_info->columns) == 0)))))
4781         {
4782           MagickOffsetType
4783             offset;
4784
4785           /*
4786             Pixels are accessed directly from memory.
4787           */
4788           offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4789             nexus_info->region.x;
4790           nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4791             offset;
4792           nexus_info->metacontent=(void *) NULL;
4793           if (cache_info->metacontent_extent != 0)
4794             nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4795               offset*cache_info->metacontent_extent;
4796           return(nexus_info->pixels);
4797         }
4798     }
4799   /*
4800     Pixels are stored in a cache region until they are synced to the cache.
4801   */
4802   number_pixels=(MagickSizeType) nexus_info->region.width*
4803     nexus_info->region.height;
4804   length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4805   if (cache_info->metacontent_extent != 0)
4806     length+=number_pixels*cache_info->metacontent_extent;
4807   if (nexus_info->cache == (Quantum *) NULL)
4808     {
4809       nexus_info->length=length;
4810       status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4811       if (status == MagickFalse)
4812         {
4813           nexus_info->length=0;
4814           return((Quantum *) NULL);
4815         }
4816     }
4817   else
4818     if (nexus_info->length != length)
4819       {
4820         RelinquishCacheNexusPixels(nexus_info);
4821         nexus_info->length=length;
4822         status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4823         if (status == MagickFalse)
4824           {
4825             nexus_info->length=0;
4826             return((Quantum *) NULL);
4827           }
4828       }
4829   nexus_info->pixels=nexus_info->cache;
4830   nexus_info->metacontent=(void *) NULL;
4831   if (cache_info->metacontent_extent != 0)
4832     nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4833       cache_info->number_channels);
4834   return(nexus_info->pixels);
4835 }
4836 \f
4837 /*
4838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4839 %                                                                             %
4840 %                                                                             %
4841 %                                                                             %
4842 %   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                       %
4843 %                                                                             %
4844 %                                                                             %
4845 %                                                                             %
4846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4847 %
4848 %  SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4849 %  pixel cache and returns the previous setting.  A virtual pixel is any pixel
4850 %  access that is outside the boundaries of the image cache.
4851 %
4852 %  The format of the SetPixelCacheVirtualMethod() method is:
4853 %
4854 %      VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4855 %        const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4856 %
4857 %  A description of each parameter follows:
4858 %
4859 %    o image: the image.
4860 %
4861 %    o virtual_pixel_method: choose the type of virtual pixel.
4862 %
4863 %    o exception: return any errors or warnings in this structure.
4864 %
4865 */
4866
4867 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4868   ExceptionInfo *exception)
4869 {
4870   CacheInfo
4871     *cache_info;
4872
4873   MagickBooleanType
4874     status;
4875
4876   ssize_t
4877     y;
4878
4879   assert(image != (Image *) NULL);
4880   assert(image->signature == MagickSignature);
4881   if (image->debug != MagickFalse)
4882     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4883   assert(image->cache != (Cache) NULL);
4884   cache_info=(CacheInfo *) image->cache;
4885   assert(cache_info->signature == MagickSignature);
4886   image->matte=MagickTrue;
4887   status=MagickTrue;
4888 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4889   #pragma omp parallel for schedule(static,4) shared(status)
4890 #endif
4891   for (y=0; y < (ssize_t) image->rows; y++)
4892   {
4893     const int
4894       id = GetOpenMPThreadId();
4895
4896     register Quantum
4897       *restrict q;
4898
4899     register ssize_t
4900       x;
4901
4902     if (status == MagickFalse)
4903       continue;
4904     q=GetAuthenticPixelCacheNexus(image,0,y,image->columns,1,
4905       cache_info->nexus_info[id],exception);
4906     if (q == (Quantum *) NULL)
4907       {
4908         status=MagickFalse;
4909         continue;
4910       }
4911     for (x=0; x < (ssize_t) image->columns; x++)
4912     {
4913       SetPixelAlpha(image,alpha,q);
4914       q+=GetPixelChannels(image);
4915     }
4916     status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4917       exception);
4918   }
4919   return(status);
4920 }
4921
4922 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4923   const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4924 {
4925   CacheInfo
4926     *cache_info;
4927
4928   VirtualPixelMethod
4929     method;
4930
4931   assert(image != (Image *) NULL);
4932   assert(image->signature == MagickSignature);
4933   if (image->debug != MagickFalse)
4934     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4935   assert(image->cache != (Cache) NULL);
4936   cache_info=(CacheInfo *) image->cache;
4937   assert(cache_info->signature == MagickSignature);
4938   method=cache_info->virtual_pixel_method;
4939   cache_info->virtual_pixel_method=virtual_pixel_method;
4940   switch (virtual_pixel_method)
4941   {
4942     case BackgroundVirtualPixelMethod:
4943     {
4944       if ((image->background_color.matte != MagickFalse) &&
4945           (image->matte == MagickFalse))
4946         (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4947       break;
4948     }
4949     case TransparentVirtualPixelMethod:
4950     {
4951       if (image->matte == MagickFalse)
4952         (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4953       break;
4954     }
4955     default:
4956       break;
4957   }
4958   return(method);
4959 }
4960 \f
4961 /*
4962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4963 %                                                                             %
4964 %                                                                             %
4965 %                                                                             %
4966 +   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                   %
4967 %                                                                             %
4968 %                                                                             %
4969 %                                                                             %
4970 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4971 %
4972 %  SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4973 %  in-memory or disk cache.  The method returns MagickTrue if the pixel region
4974 %  is synced, otherwise MagickFalse.
4975 %
4976 %  The format of the SyncAuthenticPixelCacheNexus() method is:
4977 %
4978 %      MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4979 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4980 %
4981 %  A description of each parameter follows:
4982 %
4983 %    o image: the image.
4984 %
4985 %    o nexus_info: the cache nexus to sync.
4986 %
4987 %    o exception: return any errors or warnings in this structure.
4988 %
4989 */
4990 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4991   NexusInfo *nexus_info,ExceptionInfo *exception)
4992 {
4993   CacheInfo
4994     *cache_info;
4995
4996   MagickBooleanType
4997     status;
4998
4999   /*
5000     Transfer pixels to the cache.
5001   */
5002   assert(image != (Image *) NULL);
5003   assert(image->signature == MagickSignature);
5004   if (image->cache == (Cache) NULL)
5005     ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5006   cache_info=(CacheInfo *) image->cache;
5007   assert(cache_info->signature == MagickSignature);
5008   if (cache_info->type == UndefinedCache)
5009     return(MagickFalse);
5010   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5011     return(MagickTrue);
5012   assert(cache_info->signature == MagickSignature);
5013   status=WritePixelCachePixels(cache_info,nexus_info,exception);
5014   if ((cache_info->metacontent_extent != 0) &&
5015       (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5016     return(MagickFalse);
5017   return(status);
5018 }
5019 \f
5020 /*
5021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5022 %                                                                             %
5023 %                                                                             %
5024 %                                                                             %
5025 +   S y n c A u t h e n t i c P i x e l C a c h e                             %
5026 %                                                                             %
5027 %                                                                             %
5028 %                                                                             %
5029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5030 %
5031 %  SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5032 %  or disk cache.  The method returns MagickTrue if the pixel region is synced,
5033 %  otherwise MagickFalse.
5034 %
5035 %  The format of the SyncAuthenticPixelsCache() method is:
5036 %
5037 %      MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5038 %        ExceptionInfo *exception)
5039 %
5040 %  A description of each parameter follows:
5041 %
5042 %    o image: the image.
5043 %
5044 %    o exception: return any errors or warnings in this structure.
5045 %
5046 */
5047 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5048   ExceptionInfo *exception)
5049 {
5050   CacheInfo
5051     *cache_info;
5052
5053   const int
5054     id = GetOpenMPThreadId();
5055
5056   MagickBooleanType
5057     status;
5058
5059   assert(image != (Image *) NULL);
5060   assert(image->signature == MagickSignature);
5061   assert(image->cache != (Cache) NULL);
5062   cache_info=(CacheInfo *) image->cache;
5063   assert(cache_info->signature == MagickSignature);
5064   assert(id < (int) cache_info->number_threads);
5065   status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5066     exception);
5067   return(status);
5068 }
5069 \f
5070 /*
5071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5072 %                                                                             %
5073 %                                                                             %
5074 %                                                                             %
5075 %   S y n c A u t h e n t i c P i x e l s                                     %
5076 %                                                                             %
5077 %                                                                             %
5078 %                                                                             %
5079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5080 %
5081 %  SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5082 %  The method returns MagickTrue if the pixel region is flushed, otherwise
5083 %  MagickFalse.
5084 %
5085 %  The format of the SyncAuthenticPixels() method is:
5086 %
5087 %      MagickBooleanType SyncAuthenticPixels(Image *image,
5088 %        ExceptionInfo *exception)
5089 %
5090 %  A description of each parameter follows:
5091 %
5092 %    o image: the image.
5093 %
5094 %    o exception: return any errors or warnings in this structure.
5095 %
5096 */
5097 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5098   ExceptionInfo *exception)
5099 {
5100   CacheInfo
5101     *cache_info;
5102
5103   const int
5104     id = GetOpenMPThreadId();
5105
5106   MagickBooleanType
5107     status;
5108
5109   assert(image != (Image *) NULL);
5110   assert(image->signature == MagickSignature);
5111   assert(image->cache != (Cache) NULL);
5112   cache_info=(CacheInfo *) image->cache;
5113   assert(cache_info->signature == MagickSignature);
5114   if (cache_info->methods.sync_authentic_pixels_handler !=
5115        (SyncAuthenticPixelsHandler) NULL)
5116     {
5117       status=cache_info->methods.sync_authentic_pixels_handler(image,
5118         exception);
5119       return(status);
5120     }
5121   assert(id < (int) cache_info->number_threads);
5122   status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5123     exception);
5124   return(status);
5125 }
5126 \f
5127 /*
5128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5129 %                                                                             %
5130 %                                                                             %
5131 %                                                                             %
5132 +   S y n c I m a g e P i x e l C a c h e                                     %
5133 %                                                                             %
5134 %                                                                             %
5135 %                                                                             %
5136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5137 %
5138 %  SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5139 %  The method returns MagickTrue if the pixel region is flushed, otherwise
5140 %  MagickFalse.
5141 %
5142 %  The format of the SyncImagePixelCache() method is:
5143 %
5144 %      MagickBooleanType SyncImagePixelCache(Image *image,
5145 %        ExceptionInfo *exception)
5146 %
5147 %  A description of each parameter follows:
5148 %
5149 %    o image: the image.
5150 %
5151 %    o exception: return any errors or warnings in this structure.
5152 %
5153 */
5154 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5155   ExceptionInfo *exception)
5156 {
5157   CacheInfo
5158     *cache_info;
5159
5160   assert(image != (Image *) NULL);
5161   assert(exception != (ExceptionInfo *) NULL);
5162   cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5163   return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5164 }
5165 \f
5166 /*
5167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5168 %                                                                             %
5169 %                                                                             %
5170 %                                                                             %
5171 +   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                       %
5172 %                                                                             %
5173 %                                                                             %
5174 %                                                                             %
5175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5176 %
5177 %  WritePixelCacheMetacontent() writes the meta-content to the specified region
5178 %  of the pixel cache.
5179 %
5180 %  The format of the WritePixelCacheMetacontent() method is:
5181 %
5182 %      MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5183 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5184 %
5185 %  A description of each parameter follows:
5186 %
5187 %    o cache_info: the pixel cache.
5188 %
5189 %    o nexus_info: the cache nexus to write the meta-content.
5190 %
5191 %    o exception: return any errors or warnings in this structure.
5192 %
5193 */
5194 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5195   NexusInfo *nexus_info,ExceptionInfo *exception)
5196 {
5197   MagickOffsetType
5198     count,
5199     offset;
5200
5201   MagickSizeType
5202     extent,
5203     length;
5204
5205   register const unsigned char
5206     *restrict p;
5207
5208   register ssize_t
5209     y;
5210
5211   size_t
5212     rows;
5213
5214   if (cache_info->metacontent_extent == 0)
5215     return(MagickFalse);
5216   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5217     return(MagickTrue);
5218   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5219     nexus_info->region.x;
5220   length=(MagickSizeType) nexus_info->region.width*
5221     cache_info->metacontent_extent;
5222   rows=nexus_info->region.height;
5223   extent=(MagickSizeType) length*rows;
5224   p=(unsigned char *) nexus_info->metacontent;
5225   switch (cache_info->type)
5226   {
5227     case MemoryCache:
5228     case MapCache:
5229     {
5230       register unsigned char
5231         *restrict q;
5232
5233       /*
5234         Write associated pixels to memory.
5235       */
5236       if ((cache_info->columns == nexus_info->region.width) &&
5237           (extent == (MagickSizeType) ((size_t) extent)))
5238         {
5239           length=extent;
5240           rows=1UL;
5241         }
5242       q=(unsigned char *) cache_info->metacontent+offset*
5243         cache_info->metacontent_extent;
5244       for (y=0; y < (ssize_t) rows; y++)
5245       {
5246         (void) memcpy(q,p,(size_t) length);
5247         p+=nexus_info->region.width*cache_info->metacontent_extent;
5248         q+=cache_info->columns*cache_info->metacontent_extent;
5249       }
5250       break;
5251     }
5252     case DiskCache:
5253     {
5254       /*
5255         Write associated pixels to disk.
5256       */
5257       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5258         {
5259           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5260             cache_info->cache_filename);
5261           return(MagickFalse);
5262         }
5263       if ((cache_info->columns == nexus_info->region.width) &&
5264           (extent <= MagickMaxBufferExtent))
5265         {
5266           length=extent;
5267           rows=1UL;
5268         }
5269       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5270       for (y=0; y < (ssize_t) rows; y++)
5271       {
5272         count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5273           cache_info->number_channels*sizeof(Quantum)+offset*
5274           cache_info->metacontent_extent,length,(const unsigned char *) p);
5275         if ((MagickSizeType) count != length)
5276           break;
5277         p+=nexus_info->region.width*cache_info->metacontent_extent;
5278         offset+=cache_info->columns;
5279       }
5280       if (IsFileDescriptorLimitExceeded() != MagickFalse)
5281         (void) ClosePixelCacheOnDisk(cache_info);
5282       if (y < (ssize_t) rows)
5283         {
5284           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5285             cache_info->cache_filename);
5286           return(MagickFalse);
5287         }
5288       break;
5289     }
5290     default:
5291       break;
5292   }
5293   if ((cache_info->debug != MagickFalse) &&
5294       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5295     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5296       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5297       nexus_info->region.width,(double) nexus_info->region.height,(double)
5298       nexus_info->region.x,(double) nexus_info->region.y);
5299   return(MagickTrue);
5300 }
5301 \f
5302 /*
5303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5304 %                                                                             %
5305 %                                                                             %
5306 %                                                                             %
5307 +   W r i t e C a c h e P i x e l s                                           %
5308 %                                                                             %
5309 %                                                                             %
5310 %                                                                             %
5311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5312 %
5313 %  WritePixelCachePixels() writes image pixels to the specified region of the
5314 %  pixel cache.
5315 %
5316 %  The format of the WritePixelCachePixels() method is:
5317 %
5318 %      MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5319 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5320 %
5321 %  A description of each parameter follows:
5322 %
5323 %    o cache_info: the pixel cache.
5324 %
5325 %    o nexus_info: the cache nexus to write the pixels.
5326 %
5327 %    o exception: return any errors or warnings in this structure.
5328 %
5329 */
5330 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5331   NexusInfo *nexus_info,ExceptionInfo *exception)
5332 {
5333   MagickOffsetType
5334     count,
5335     offset;
5336
5337   MagickSizeType
5338     extent,
5339     length;
5340
5341   register const Quantum
5342     *restrict p;
5343
5344   register ssize_t
5345     y;
5346
5347   size_t
5348     rows;
5349
5350   if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5351     return(MagickTrue);
5352   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5353     nexus_info->region.x;
5354   length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5355     sizeof(Quantum);
5356   rows=nexus_info->region.height;
5357   extent=length*rows;
5358   p=nexus_info->pixels;
5359   switch (cache_info->type)
5360   {
5361     case MemoryCache:
5362     case MapCache:
5363     {
5364       register Quantum
5365         *restrict q;
5366
5367       /*
5368         Write pixels to memory.
5369       */
5370       if ((cache_info->columns == nexus_info->region.width) &&
5371           (extent == (MagickSizeType) ((size_t) extent)))
5372         {
5373           length=extent;
5374           rows=1UL;
5375         }
5376       q=cache_info->pixels+offset*cache_info->number_channels;
5377       for (y=0; y < (ssize_t) rows; y++)
5378       {
5379         (void) memcpy(q,p,(size_t) length);
5380         p+=nexus_info->region.width*cache_info->number_channels;
5381         q+=cache_info->columns*cache_info->number_channels;
5382       }
5383       break;
5384     }
5385     case DiskCache:
5386     {
5387       /*
5388         Write pixels to disk.
5389       */
5390       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5391         {
5392           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5393             cache_info->cache_filename);
5394           return(MagickFalse);
5395         }
5396       if ((cache_info->columns == nexus_info->region.width) &&
5397           (extent <= MagickMaxBufferExtent))
5398         {
5399           length=extent;
5400           rows=1UL;
5401         }
5402       for (y=0; y < (ssize_t) rows; y++)
5403       {
5404         count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5405           cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5406           p);
5407         if ((MagickSizeType) count != length)
5408           break;
5409         p+=nexus_info->region.width*cache_info->number_channels;
5410         offset+=cache_info->columns;
5411       }
5412       if (IsFileDescriptorLimitExceeded() != MagickFalse)
5413         (void) ClosePixelCacheOnDisk(cache_info);
5414       if (y < (ssize_t) rows)
5415         {
5416           ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5417             cache_info->cache_filename);
5418           return(MagickFalse);
5419         }
5420       break;
5421     }
5422     default:
5423       break;
5424   }
5425   if ((cache_info->debug != MagickFalse) &&
5426       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5427     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5428       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5429       nexus_info->region.width,(double) nexus_info->region.height,(double)
5430       nexus_info->region.x,(double) nexus_info->region.y);
5431   return(MagickTrue);
5432 }