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