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