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