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