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