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