]> 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
1963 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1964 {
1965   CacheInfo
1966     *cache_info;
1967
1968   /*
1969     Does the image match the pixel cache morphology?
1970   */
1971   cache_info=(CacheInfo *) image->cache;
1972   if ((image->storage_class != cache_info->storage_class) ||
1973       (image->colorspace != cache_info->colorspace) ||
1974       (image->matte != cache_info->matte) ||
1975       (image->columns != cache_info->columns) ||
1976       (image->rows != cache_info->rows) ||
1977       (image->number_channels != cache_info->number_channels) ||
1978       (image->metacontent_extent != cache_info->metacontent_extent) ||
1979       (cache_info->nexus_info == (NexusInfo **) NULL) ||
1980       (cache_info->number_threads < GetOpenMPMaximumThreads()))
1981     return(MagickFalse);
1982   return(MagickTrue);
1983 }
1984
1985 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1986   ExceptionInfo *exception)
1987 {
1988   CacheInfo
1989     *cache_info;
1990
1991   MagickBooleanType
1992     destroy,
1993     status;
1994
1995   static MagickSizeType
1996     cpu_throttle = 0,
1997     cycles = 0,
1998     time_limit = 0;
1999
2000   static time_t
2001     cache_genesis = 0;
2002
2003   status=MagickTrue;
2004   LockSemaphoreInfo(image->semaphore);
2005   if (cpu_throttle == 0)
2006     {
2007       char
2008         *limit;
2009
2010       /*
2011         Set CPU throttle in milleseconds.
2012       */
2013       cpu_throttle=MagickResourceInfinity;
2014       limit=GetEnvironmentValue("MAGICK_THROTTLE");
2015       if (limit == (char *) NULL)
2016         limit=GetPolicyValue("throttle");
2017       if (limit != (char *) NULL)
2018         {
2019           cpu_throttle=(MagickSizeType) StringToInteger(limit);
2020           limit=DestroyString(limit);
2021         }
2022     }
2023   if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2024     MagickDelay(cpu_throttle);
2025   if (time_limit == 0)
2026     {
2027       /*
2028         Set the exire time in seconds.
2029       */
2030       time_limit=GetMagickResourceLimit(TimeResource);
2031       cache_genesis=time((time_t *) NULL);
2032     }
2033   if ((time_limit != MagickResourceInfinity) &&
2034       ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
2035     ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2036   assert(image->cache != (Cache) NULL);
2037   cache_info=(CacheInfo *) image->cache;
2038   destroy=MagickFalse;
2039   if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2040     {
2041       LockSemaphoreInfo(cache_info->semaphore);
2042       if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2043         {
2044           Image
2045             clone_image;
2046
2047           CacheInfo
2048             *clone_info;
2049
2050           /*
2051             Clone pixel cache.
2052           */
2053           clone_image=(*image);
2054           clone_image.semaphore=AllocateSemaphoreInfo();
2055           clone_image.reference_count=1;
2056           clone_image.cache=ClonePixelCache(cache_info);
2057           clone_info=(CacheInfo *) clone_image.cache;
2058           status=OpenPixelCache(&clone_image,IOMode,exception);
2059           if (status != MagickFalse)
2060             {
2061               if (clone != MagickFalse)
2062                 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2063               if (status != MagickFalse)
2064                 {
2065                   destroy=MagickTrue;
2066                   image->cache=clone_image.cache;
2067                 }
2068             }
2069           DestroySemaphoreInfo(&clone_image.semaphore);
2070         }
2071       UnlockSemaphoreInfo(cache_info->semaphore);
2072     }
2073   if (destroy != MagickFalse)
2074     cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2075   if (status != MagickFalse)
2076     {
2077       /*
2078         Ensure the image matches the pixel cache morphology.
2079       */
2080       image->taint=MagickTrue;
2081       image->type=UndefinedType;
2082       if (1 && image->colorspace == GRAYColorspace)
2083         image->colorspace=RGBColorspace;
2084       if (ValidatePixelCacheMorphology(image) == MagickFalse)
2085         status=OpenPixelCache(image,IOMode,exception);
2086     }
2087   UnlockSemaphoreInfo(image->semaphore);
2088   if (status == MagickFalse)
2089     return((Cache) NULL);
2090   return(image->cache);
2091 }
2092 \f
2093 /*
2094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2095 %                                                                             %
2096 %                                                                             %
2097 %                                                                             %
2098 %   G e t O n e A u t h e n t i c P i x e l                                   %
2099 %                                                                             %
2100 %                                                                             %
2101 %                                                                             %
2102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2103 %
2104 %  GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2105 %  location.  The image background color is returned if an error occurs.
2106 %
2107 %  The format of the GetOneAuthenticPixel() method is:
2108 %
2109 %      MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2110 %        const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2111 %
2112 %  A description of each parameter follows:
2113 %
2114 %    o image: the image.
2115 %
2116 %    o x,y:  These values define the location of the pixel to return.
2117 %
2118 %    o pixel: return a pixel at the specified (x,y) location.
2119 %
2120 %    o exception: return any errors or warnings in this structure.
2121 %
2122 */
2123 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2124   const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2125 {
2126   CacheInfo
2127     *cache_info;
2128
2129   register Quantum
2130     *q;
2131
2132   assert(image != (Image *) NULL);
2133   assert(image->signature == MagickSignature);
2134   assert(image->cache != (Cache) NULL);
2135   cache_info=(CacheInfo *) image->cache;
2136   assert(cache_info->signature == MagickSignature);
2137   *pixel=image->background_color;
2138   if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2139        (GetOneAuthenticPixelFromHandler) NULL)
2140     return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2141       pixel,exception));
2142   q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2143   if (q == (Quantum *) NULL)
2144     return(MagickFalse);
2145   GetPixelPacket(image,q,pixel);
2146   return(MagickTrue);
2147 }
2148 \f
2149 /*
2150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2151 %                                                                             %
2152 %                                                                             %
2153 %                                                                             %
2154 +   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                 %
2155 %                                                                             %
2156 %                                                                             %
2157 %                                                                             %
2158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2159 %
2160 %  GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2161 %  location.  The image background color is returned if an error occurs.
2162 %
2163 %  The format of the GetOneAuthenticPixelFromCache() method is:
2164 %
2165 %      MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2166 %        const ssize_t x,const ssize_t y,PixelPacket *pixel,
2167 %        ExceptionInfo *exception)
2168 %
2169 %  A description of each parameter follows:
2170 %
2171 %    o image: the image.
2172 %
2173 %    o x,y:  These values define the location of the pixel to return.
2174 %
2175 %    o pixel: return a pixel at the specified (x,y) location.
2176 %
2177 %    o exception: return any errors or warnings in this structure.
2178 %
2179 */
2180 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2181   const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2182 {
2183   CacheInfo
2184     *cache_info;
2185
2186   const int
2187     id = GetOpenMPThreadId();
2188
2189   register Quantum
2190     *q;
2191
2192   assert(image != (const Image *) NULL);
2193   assert(image->signature == MagickSignature);
2194   assert(image->cache != (Cache) NULL);
2195   cache_info=(CacheInfo *) image->cache;
2196   assert(cache_info->signature == MagickSignature);
2197   assert(id < (int) cache_info->number_threads);
2198   *pixel=image->background_color;
2199   q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2200     exception);
2201   if (q == (Quantum *) NULL)
2202     return(MagickFalse);
2203   GetPixelPacket(image,q,pixel);
2204   return(MagickTrue);
2205 }
2206 \f
2207 /*
2208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2209 %                                                                             %
2210 %                                                                             %
2211 %                                                                             %
2212 %   G e t O n e V i r t u a l M a g i c k P i x e l                           %
2213 %                                                                             %
2214 %                                                                             %
2215 %                                                                             %
2216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2217 %
2218 %  GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2219 %  location.  The image background color is returned if an error occurs.  If
2220 %  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2221 %
2222 %  The format of the GetOneVirtualMagickPixel() method is:
2223 %
2224 %      MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2225 %        const ssize_t x,const ssize_t y,PixelInfo *pixel,
2226 %        ExceptionInfo exception)
2227 %
2228 %  A description of each parameter follows:
2229 %
2230 %    o image: the image.
2231 %
2232 %    o x,y:  these values define the location of the pixel to return.
2233 %
2234 %    o pixel: return a pixel at the specified (x,y) location.
2235 %
2236 %    o exception: return any errors or warnings in this structure.
2237 %
2238 */
2239 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2240   const ssize_t x,const ssize_t y,PixelInfo *pixel,
2241   ExceptionInfo *exception)
2242 {
2243   CacheInfo
2244     *cache_info;
2245
2246   const int
2247     id = GetOpenMPThreadId();
2248
2249   register const Quantum
2250     *pixels;
2251
2252   assert(image != (const Image *) NULL);
2253   assert(image->signature == MagickSignature);
2254   assert(image->cache != (Cache) NULL);
2255   cache_info=(CacheInfo *) image->cache;
2256   assert(cache_info->signature == MagickSignature);
2257   assert(id < (int) cache_info->number_threads);
2258   pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2259     1UL,1UL,cache_info->nexus_info[id],exception);
2260   GetPixelInfo(image,pixel);
2261   if (pixels == (const Quantum *) NULL)
2262     return(MagickFalse);
2263   SetPixelInfo(image,pixels,pixel);
2264   return(MagickTrue);
2265 }
2266 \f
2267 /*
2268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2269 %                                                                             %
2270 %                                                                             %
2271 %                                                                             %
2272 %   G e t O n e V i r t u a l M e t h o d P i x e l                           %
2273 %                                                                             %
2274 %                                                                             %
2275 %                                                                             %
2276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2277 %
2278 %  GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2279 %  location as defined by specified pixel method.  The image background color
2280 %  is returned if an error occurs.  If you plan to modify the pixel, use
2281 %  GetOneAuthenticPixel() instead.
2282 %
2283 %  The format of the GetOneVirtualMethodPixel() method is:
2284 %
2285 %      MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2286 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2287 %        const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
2288 %
2289 %  A description of each parameter follows:
2290 %
2291 %    o image: the image.
2292 %
2293 %    o virtual_pixel_method: the virtual pixel method.
2294 %
2295 %    o x,y:  These values define the location of the pixel to return.
2296 %
2297 %    o pixel: return a pixel at the specified (x,y) location.
2298 %
2299 %    o exception: return any errors or warnings in this structure.
2300 %
2301 */
2302 MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2303   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2304   PixelPacket *pixel,ExceptionInfo *exception)
2305 {
2306   CacheInfo
2307     *cache_info;
2308
2309   const int
2310     id = GetOpenMPThreadId();
2311
2312   const Quantum
2313     *p;
2314
2315   assert(image != (const Image *) NULL);
2316   assert(image->signature == MagickSignature);
2317   assert(image->cache != (Cache) NULL);
2318   cache_info=(CacheInfo *) image->cache;
2319   assert(cache_info->signature == MagickSignature);
2320   *pixel=image->background_color;
2321   if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2322        (GetOneVirtualPixelFromHandler) NULL)
2323     return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2324       virtual_pixel_method,x,y,pixel,exception));
2325   assert(id < (int) cache_info->number_threads);
2326   p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2327     cache_info->nexus_info[id],exception);
2328   if (p == (const Quantum *) NULL)
2329     return(MagickFalse);
2330   GetPixelPacket(image,p,pixel);
2331   if (image->colorspace == CMYKColorspace)
2332     pixel->black=GetPixelBlack(image,p);
2333   return(MagickTrue);
2334 }
2335 \f
2336 /*
2337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2338 %                                                                             %
2339 %                                                                             %
2340 %                                                                             %
2341 %   G e t O n e V i r t u a l P i x e l                                       %
2342 %                                                                             %
2343 %                                                                             %
2344 %                                                                             %
2345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2346 %
2347 %  GetOneVirtualPixel() returns a single virtual pixel at the specified
2348 %  (x,y) location.  The image background color is returned if an error occurs.
2349 %  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2350 %
2351 %  The format of the GetOneVirtualPixel() method is:
2352 %
2353 %      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2354 %        const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
2355 %
2356 %  A description of each parameter follows:
2357 %
2358 %    o image: the image.
2359 %
2360 %    o x,y:  These values define the location of the pixel to return.
2361 %
2362 %    o pixel: return a pixel at the specified (x,y) location.
2363 %
2364 %    o exception: return any errors or warnings in this structure.
2365 %
2366 */
2367 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2368   const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2369 {
2370   CacheInfo
2371     *cache_info;
2372
2373   const int
2374     id = GetOpenMPThreadId();
2375
2376   const Quantum
2377     *p;
2378
2379   assert(image != (const Image *) NULL);
2380   assert(image->signature == MagickSignature);
2381   assert(image->cache != (Cache) NULL);
2382   cache_info=(CacheInfo *) image->cache;
2383   assert(cache_info->signature == MagickSignature);
2384   *pixel=image->background_color;
2385   if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2386        (GetOneVirtualPixelFromHandler) NULL)
2387     return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2388       GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2389   assert(id < (int) cache_info->number_threads);
2390   p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2391     1UL,1UL,cache_info->nexus_info[id],exception);
2392   if (p == (const Quantum *) NULL)
2393     return(MagickFalse);
2394   GetPixelPacket(image,p,pixel);
2395   if (image->colorspace == CMYKColorspace)
2396     pixel->black=GetPixelBlack(image,p);
2397   return(MagickTrue);
2398 }
2399 \f
2400 /*
2401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2402 %                                                                             %
2403 %                                                                             %
2404 %                                                                             %
2405 +   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                     %
2406 %                                                                             %
2407 %                                                                             %
2408 %                                                                             %
2409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2410 %
2411 %  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2412 %  specified (x,y) location.  The image background color is returned if an
2413 %  error occurs.
2414 %
2415 %  The format of the GetOneVirtualPixelFromCache() method is:
2416 %
2417 %      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2418 %        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2419 %        PixelPacket *pixel,ExceptionInfo *exception)
2420 %
2421 %  A description of each parameter follows:
2422 %
2423 %    o image: the image.
2424 %
2425 %    o virtual_pixel_method: the virtual pixel method.
2426 %
2427 %    o x,y:  These values define the location of the pixel to return.
2428 %
2429 %    o pixel: return a pixel at the specified (x,y) location.
2430 %
2431 %    o exception: return any errors or warnings in this structure.
2432 %
2433 */
2434 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2435   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2436   PixelPacket *pixel,ExceptionInfo *exception)
2437 {
2438   CacheInfo
2439     *cache_info;
2440
2441   const int
2442     id = GetOpenMPThreadId();
2443
2444   const Quantum
2445     *p;
2446
2447   assert(image != (const Image *) NULL);
2448   assert(image->signature == MagickSignature);
2449   assert(image->cache != (Cache) NULL);
2450   cache_info=(CacheInfo *) image->cache;
2451   assert(cache_info->signature == MagickSignature);
2452   assert(id < (int) cache_info->number_threads);
2453   *pixel=image->background_color;
2454   p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2455     cache_info->nexus_info[id],exception);
2456   if (p == (const Quantum *) NULL)
2457     return(MagickFalse);
2458   GetPixelPacket(image,p,pixel);
2459   if (image->colorspace == CMYKColorspace)
2460     pixel->black=GetPixelBlack(image,p);
2461   return(MagickTrue);
2462 }
2463 \f
2464 /*
2465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466 %                                                                             %
2467 %                                                                             %
2468 %                                                                             %
2469 +   G e t P i x e l C a c h e C o l o r s p a c e                             %
2470 %                                                                             %
2471 %                                                                             %
2472 %                                                                             %
2473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2474 %
2475 %  GetPixelCacheColorspace() returns the class type of the pixel cache.
2476 %
2477 %  The format of the GetPixelCacheColorspace() method is:
2478 %
2479 %      Colorspace GetPixelCacheColorspace(Cache cache)
2480 %
2481 %  A description of each parameter follows:
2482 %
2483 %    o cache: the pixel cache.
2484 %
2485 */
2486 MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2487 {
2488   CacheInfo
2489     *cache_info;
2490
2491   assert(cache != (Cache) NULL);
2492   cache_info=(CacheInfo *) cache;
2493   assert(cache_info->signature == MagickSignature);
2494   if (cache_info->debug != MagickFalse)
2495     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2496       cache_info->filename);
2497   return(cache_info->colorspace);
2498 }
2499 \f
2500 /*
2501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2502 %                                                                             %
2503 %                                                                             %
2504 %                                                                             %
2505 +   G e t P i x e l C a c h e M e t h o d s                                   %
2506 %                                                                             %
2507 %                                                                             %
2508 %                                                                             %
2509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2510 %
2511 %  GetPixelCacheMethods() initializes the CacheMethods structure.
2512 %
2513 %  The format of the GetPixelCacheMethods() method is:
2514 %
2515 %      void GetPixelCacheMethods(CacheMethods *cache_methods)
2516 %
2517 %  A description of each parameter follows:
2518 %
2519 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
2520 %
2521 */
2522 MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2523 {
2524   assert(cache_methods != (CacheMethods *) NULL);
2525   (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2526   cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2527   cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2528   cache_methods->get_virtual_metacontent_from_handler=
2529     GetVirtualMetacontentFromCache;
2530   cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2531   cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2532   cache_methods->get_authentic_metacontent_from_handler=
2533     GetAuthenticMetacontentFromCache;
2534   cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2535   cache_methods->get_one_authentic_pixel_from_handler=
2536     GetOneAuthenticPixelFromCache;
2537   cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2538   cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2539   cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2540 }
2541 \f
2542 /*
2543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2544 %                                                                             %
2545 %                                                                             %
2546 %                                                                             %
2547 +   G e t P i x e l C a c h e N e x u s E x t e n t                           %
2548 %                                                                             %
2549 %                                                                             %
2550 %                                                                             %
2551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2552 %
2553 %  GetPixelCacheNexusExtent() returns the extent of the pixels associated
2554 %  corresponding with the last call to SetPixelCacheNexusPixels() or
2555 %  GetPixelCacheNexusPixels().
2556 %
2557 %  The format of the GetPixelCacheNexusExtent() method is:
2558 %
2559 %      MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2560 %        NexusInfo *nexus_info)
2561 %
2562 %  A description of each parameter follows:
2563 %
2564 %    o nexus_info: the nexus info.
2565 %
2566 */
2567 MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2568   NexusInfo *nexus_info)
2569 {
2570   CacheInfo
2571     *cache_info;
2572
2573   MagickSizeType
2574     extent;
2575
2576   assert(cache != (const Cache) NULL);
2577   cache_info=(CacheInfo *) cache;
2578   assert(cache_info->signature == MagickSignature);
2579   extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2580   if (extent == 0)
2581     return((MagickSizeType) cache_info->columns*cache_info->rows);
2582   return(extent);
2583 }
2584 \f
2585 /*
2586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2587 %                                                                             %
2588 %                                                                             %
2589 %                                                                             %
2590 +   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                 %
2591 %                                                                             %
2592 %                                                                             %
2593 %                                                                             %
2594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2595 %
2596 %  GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2597 %  cache nexus.
2598 %
2599 %  The format of the GetPixelCacheNexusMetacontent() method is:
2600 %
2601 %      void *GetPixelCacheNexusMetacontent(const Cache cache,
2602 %        NexusInfo *nexus_info)
2603 %
2604 %  A description of each parameter follows:
2605 %
2606 %    o cache: the pixel cache.
2607 %
2608 %    o nexus_info: the cache nexus to return the meta-content.
2609 %
2610 */
2611 MagickExport void *GetPixelCacheNexusMetacontent(const Cache cache,
2612   NexusInfo *nexus_info)
2613 {
2614   CacheInfo
2615     *cache_info;
2616
2617   assert(cache != (const Cache) NULL);
2618   cache_info=(CacheInfo *) cache;
2619   assert(cache_info->signature == MagickSignature);
2620   if (cache_info->storage_class == UndefinedClass)
2621     return((void *) NULL);
2622   return(nexus_info->metacontent);
2623 }
2624 \f
2625 /*
2626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2627 %                                                                             %
2628 %                                                                             %
2629 %                                                                             %
2630 +   G e t P i x e l C a c h e N e x u s P i x e l s                           %
2631 %                                                                             %
2632 %                                                                             %
2633 %                                                                             %
2634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2635 %
2636 %  GetPixelCacheNexusPixels() returns the pixels associated with the specified
2637 %  cache nexus.
2638 %
2639 %  The format of the GetPixelCacheNexusPixels() method is:
2640 %
2641 %      Quantum *GetPixelCacheNexusPixels(const Cache cache,
2642 %        NexusInfo *nexus_info)
2643 %
2644 %  A description of each parameter follows:
2645 %
2646 %    o cache: the pixel cache.
2647 %
2648 %    o nexus_info: the cache nexus to return the pixels.
2649 %
2650 */
2651 MagickExport Quantum *GetPixelCacheNexusPixels(const Cache cache,
2652   NexusInfo *nexus_info)
2653 {
2654   CacheInfo
2655     *cache_info;
2656
2657   assert(cache != (const Cache) NULL);
2658   cache_info=(CacheInfo *) cache;
2659   assert(cache_info->signature == MagickSignature);
2660   if (cache_info->storage_class == UndefinedClass)
2661     return((Quantum *) NULL);
2662   return(nexus_info->pixels);
2663 }
2664 \f
2665 /*
2666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2667 %                                                                             %
2668 %                                                                             %
2669 %                                                                             %
2670 +   G e t P i x e l C a c h e P i x e l s                                     %
2671 %                                                                             %
2672 %                                                                             %
2673 %                                                                             %
2674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675 %
2676 %  GetPixelCachePixels() returns the pixels associated with the specified image.
2677 %
2678 %  The format of the GetPixelCachePixels() method is:
2679 %
2680 %      void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2681 %        ExceptionInfo *exception)
2682 %
2683 %  A description of each parameter follows:
2684 %
2685 %    o image: the image.
2686 %
2687 %    o length: the pixel cache length.
2688 %
2689 %    o exception: return any errors or warnings in this structure.
2690 %
2691 */
2692 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2693   ExceptionInfo *exception)
2694 {
2695   CacheInfo
2696     *cache_info;
2697
2698   assert(image != (const Image *) NULL);
2699   assert(image->signature == MagickSignature);
2700   assert(image->cache != (Cache) NULL);
2701   assert(length != (MagickSizeType *) NULL);
2702   assert(exception != (ExceptionInfo *) NULL);
2703   assert(exception->signature == MagickSignature);
2704   cache_info=(CacheInfo *) image->cache;
2705   assert(cache_info->signature == MagickSignature);
2706   *length=0;
2707   if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2708     return((void *) NULL);
2709   *length=cache_info->length;
2710   return((void *) cache_info->pixels);
2711 }
2712 \f
2713 /*
2714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2715 %                                                                             %
2716 %                                                                             %
2717 %                                                                             %
2718 +   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                         %
2719 %                                                                             %
2720 %                                                                             %
2721 %                                                                             %
2722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2723 %
2724 %  GetPixelCacheStorageClass() returns the class type of the pixel cache.
2725 %
2726 %  The format of the GetPixelCacheStorageClass() method is:
2727 %
2728 %      ClassType GetPixelCacheStorageClass(Cache cache)
2729 %
2730 %  A description of each parameter follows:
2731 %
2732 %    o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2733 %
2734 %    o cache: the pixel cache.
2735 %
2736 */
2737 MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2738 {
2739   CacheInfo
2740     *cache_info;
2741
2742   assert(cache != (Cache) NULL);
2743   cache_info=(CacheInfo *) cache;
2744   assert(cache_info->signature == MagickSignature);
2745   if (cache_info->debug != MagickFalse)
2746     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2747       cache_info->filename);
2748   return(cache_info->storage_class);
2749 }
2750 \f
2751 /*
2752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2753 %                                                                             %
2754 %                                                                             %
2755 %                                                                             %
2756 +   G e t P i x e l C a c h e T i l e S i z e                                 %
2757 %                                                                             %
2758 %                                                                             %
2759 %                                                                             %
2760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2761 %
2762 %  GetPixelCacheTileSize() returns the pixel cache tile size.
2763 %
2764 %  The format of the GetPixelCacheTileSize() method is:
2765 %
2766 %      void GetPixelCacheTileSize(const Image *image,size_t *width,
2767 %        size_t *height)
2768 %
2769 %  A description of each parameter follows:
2770 %
2771 %    o image: the image.
2772 %
2773 %    o width: the optimize cache tile width in pixels.
2774 %
2775 %    o height: the optimize cache tile height in pixels.
2776 %
2777 */
2778 MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2779   size_t *height)
2780 {
2781   CacheInfo
2782     *cache_info;
2783
2784   assert(image != (Image *) NULL);
2785   assert(image->signature == MagickSignature);
2786   if (image->debug != MagickFalse)
2787     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2788   cache_info=(CacheInfo *) image->cache;
2789   assert(cache_info->signature == MagickSignature);
2790   *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2791   if (GetPixelCacheType(image) == DiskCache)
2792     *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2793   *height=(*width);
2794 }
2795 \f
2796 /*
2797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2798 %                                                                             %
2799 %                                                                             %
2800 %                                                                             %
2801 +   G e t P i x e l C a c h e T y p e                                         %
2802 %                                                                             %
2803 %                                                                             %
2804 %                                                                             %
2805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2806 %
2807 %  GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2808 %
2809 %  The format of the GetPixelCacheType() method is:
2810 %
2811 %      CacheType GetPixelCacheType(const Image *image)
2812 %
2813 %  A description of each parameter follows:
2814 %
2815 %    o image: the image.
2816 %
2817 */
2818 MagickExport CacheType GetPixelCacheType(const Image *image)
2819 {
2820   CacheInfo
2821     *cache_info;
2822
2823   assert(image != (Image *) NULL);
2824   assert(image->signature == MagickSignature);
2825   assert(image->cache != (Cache) NULL);
2826   cache_info=(CacheInfo *) image->cache;
2827   assert(cache_info->signature == MagickSignature);
2828   return(cache_info->type);
2829 }
2830 \f
2831 /*
2832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2833 %                                                                             %
2834 %                                                                             %
2835 %                                                                             %
2836 +   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                       %
2837 %                                                                             %
2838 %                                                                             %
2839 %                                                                             %
2840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2841 %
2842 %  GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2843 %  pixel cache.  A virtual pixel is any pixel access that is outside the
2844 %  boundaries of the image cache.
2845 %
2846 %  The format of the GetPixelCacheVirtualMethod() method is:
2847 %
2848 %      VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2849 %
2850 %  A description of each parameter follows:
2851 %
2852 %    o image: the image.
2853 %
2854 */
2855 MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2856 {
2857   CacheInfo
2858     *cache_info;
2859
2860   assert(image != (Image *) NULL);
2861   assert(image->signature == MagickSignature);
2862   assert(image->cache != (Cache) NULL);
2863   cache_info=(CacheInfo *) image->cache;
2864   assert(cache_info->signature == MagickSignature);
2865   return(cache_info->virtual_pixel_method);
2866 }
2867 \f
2868 /*
2869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2870 %                                                                             %
2871 %                                                                             %
2872 %                                                                             %
2873 +   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               %
2874 %                                                                             %
2875 %                                                                             %
2876 %                                                                             %
2877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2878 %
2879 %  GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2880 %  the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2881 %
2882 %  The format of the GetVirtualMetacontentFromCache() method is:
2883 %
2884 %      void *GetVirtualMetacontentFromCache(const Image *image)
2885 %
2886 %  A description of each parameter follows:
2887 %
2888 %    o image: the image.
2889 %
2890 */
2891 static const void *GetVirtualMetacontentFromCache(const Image *image)
2892 {
2893   CacheInfo
2894     *cache_info;
2895
2896   const int
2897     id = GetOpenMPThreadId();
2898
2899   const void
2900     *metacontent;
2901
2902   assert(image != (const Image *) NULL);
2903   assert(image->signature == MagickSignature);
2904   assert(image->cache != (Cache) NULL);
2905   cache_info=(CacheInfo *) image->cache;
2906   assert(cache_info->signature == MagickSignature);
2907   assert(id < (int) cache_info->number_threads);
2908   metacontent=GetVirtualMetacontentFromNexus(cache_info,
2909     cache_info->nexus_info[id]);
2910   return(metacontent);
2911 }
2912 \f
2913 /*
2914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2915 %                                                                             %
2916 %                                                                             %
2917 %                                                                             %
2918 +   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               %
2919 %                                                                             %
2920 %                                                                             %
2921 %                                                                             %
2922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2923 %
2924 %  GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2925 %  cache nexus.
2926 %
2927 %  The format of the GetVirtualMetacontentFromNexus() method is:
2928 %
2929 %      const void *GetVirtualMetacontentFromNexus(const Cache cache,
2930 %        NexusInfo *nexus_info)
2931 %
2932 %  A description of each parameter follows:
2933 %
2934 %    o cache: the pixel cache.
2935 %
2936 %    o nexus_info: the cache nexus to return the meta-content.
2937 %
2938 */
2939 MagickExport const void *GetVirtualMetacontentFromNexus(const Cache cache,
2940   NexusInfo *nexus_info)
2941 {
2942   CacheInfo
2943     *cache_info;
2944
2945   assert(cache != (Cache) NULL);
2946   cache_info=(CacheInfo *) cache;
2947   assert(cache_info->signature == MagickSignature);
2948   if (cache_info->storage_class == UndefinedClass)
2949     return((void *) NULL);
2950   return(nexus_info->metacontent);
2951 }
2952 \f
2953 /*
2954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2955 %                                                                             %
2956 %                                                                             %
2957 %                                                                             %
2958 %   G e t V i r t u a l M e t a c o n t e n t                                 %
2959 %                                                                             %
2960 %                                                                             %
2961 %                                                                             %
2962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2963 %
2964 %  GetVirtualMetacontent() returns the virtual metacontent corresponding with
2965 %  the last call to QueueAuthenticPixels() or GetVirtualPixels().  NULL is
2966 %  returned if the meta-content are not available.
2967 %
2968 %  The format of the GetVirtualMetacontent() method is:
2969 %
2970 %      const void *GetVirtualMetacontent(const Image *image)
2971 %
2972 %  A description of each parameter follows:
2973 %
2974 %    o image: the image.
2975 %
2976 */
2977 MagickExport const void *GetVirtualMetacontent(const Image *image)
2978 {
2979   CacheInfo
2980     *cache_info;
2981
2982   const int
2983     id = GetOpenMPThreadId();
2984
2985   const void
2986     *metacontent;
2987
2988   assert(image != (const Image *) NULL);
2989   assert(image->signature == MagickSignature);
2990   assert(image->cache != (Cache) NULL);
2991   cache_info=(CacheInfo *) image->cache;
2992   assert(cache_info->signature == MagickSignature);
2993   if (cache_info->methods.get_virtual_metacontent_from_handler !=
2994        (GetVirtualMetacontentFromHandler) NULL)
2995     {
2996       metacontent=cache_info->methods.
2997         get_virtual_metacontent_from_handler(image);
2998       return(metacontent);
2999     }
3000   assert(id < (int) cache_info->number_threads);
3001   metacontent=GetVirtualMetacontentFromNexus(cache_info,
3002     cache_info->nexus_info[id]);
3003   return(metacontent);
3004 }
3005 \f
3006 /*
3007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3008 %                                                                             %
3009 %                                                                             %
3010 %                                                                             %
3011 +   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                         %
3012 %                                                                             %
3013 %                                                                             %
3014 %                                                                             %
3015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3016 %
3017 %  GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3018 %  pixel cache as defined by the geometry parameters.   A pointer to the pixels
3019 %  is returned if the pixels are transferred, otherwise a NULL is returned.
3020 %
3021 %  The format of the GetVirtualPixelsFromNexus() method is:
3022 %
3023 %      Quantum *GetVirtualPixelsFromNexus(const Image *image,
3024 %        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3025 %        const size_t columns,const size_t rows,NexusInfo *nexus_info,
3026 %        ExceptionInfo *exception)
3027 %
3028 %  A description of each parameter follows:
3029 %
3030 %    o image: the image.
3031 %
3032 %    o virtual_pixel_method: the virtual pixel method.
3033 %
3034 %    o x,y,columns,rows:  These values define the perimeter of a region of
3035 %      pixels.
3036 %
3037 %    o nexus_info: the cache nexus to acquire.
3038 %
3039 %    o exception: return any errors or warnings in this structure.
3040 %
3041 */
3042
3043 static ssize_t
3044   DitherMatrix[64] =
3045   {
3046      0,  48,  12,  60,   3,  51,  15,  63,
3047     32,  16,  44,  28,  35,  19,  47,  31,
3048      8,  56,   4,  52,  11,  59,   7,  55,
3049     40,  24,  36,  20,  43,  27,  39,  23,
3050      2,  50,  14,  62,   1,  49,  13,  61,
3051     34,  18,  46,  30,  33,  17,  45,  29,
3052     10,  58,   6,  54,   9,  57,   5,  53,
3053     42,  26,  38,  22,  41,  25,  37,  21
3054   };
3055
3056 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3057 {
3058   ssize_t
3059     index;
3060
3061   index=x+DitherMatrix[x & 0x07]-32L;
3062   if (index < 0L)
3063     return(0L);
3064   if (index >= (ssize_t) columns)
3065     return((ssize_t) columns-1L);
3066   return(index);
3067 }
3068
3069 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3070 {
3071   ssize_t
3072     index;
3073
3074   index=y+DitherMatrix[y & 0x07]-32L;
3075   if (index < 0L)
3076     return(0L);
3077   if (index >= (ssize_t) rows)
3078     return((ssize_t) rows-1L);
3079   return(index);
3080 }
3081
3082 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3083 {
3084   if (x < 0L)
3085     return(0L);
3086   if (x >= (ssize_t) columns)
3087     return((ssize_t) (columns-1));
3088   return(x);
3089 }
3090
3091 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3092 {
3093   if (y < 0L)
3094     return(0L);
3095   if (y >= (ssize_t) rows)
3096     return((ssize_t) (rows-1));
3097   return(y);
3098 }
3099
3100 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3101 {
3102   return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3103 }
3104
3105 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3106 {
3107   return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3108 }
3109
3110 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3111   const size_t extent)
3112 {
3113   MagickModulo
3114     modulo;
3115
3116   /*
3117     Compute the remainder of dividing offset by extent.  It returns not only
3118     the quotient (tile the offset falls in) but also the positive remainer
3119     within that tile such that 0 <= remainder < extent.  This method is
3120     essentially a ldiv() using a floored modulo division rather than the
3121     normal default truncated modulo division.
3122   */
3123   modulo.quotient=offset/(ssize_t) extent;
3124   if (offset < 0L)
3125     modulo.quotient--;
3126   modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3127   return(modulo);
3128 }
3129
3130 MagickExport const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3131   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3132   const size_t columns,const size_t rows,NexusInfo *nexus_info,
3133   ExceptionInfo *exception)
3134 {
3135   CacheInfo
3136     *cache_info;
3137
3138   MagickOffsetType
3139     offset;
3140
3141   MagickSizeType
3142     length,
3143     number_pixels;
3144
3145   NexusInfo
3146     **virtual_nexus;
3147
3148   Quantum
3149     *pixels,
3150     virtual_pixel[MaxPixelChannels];
3151
3152   RectangleInfo
3153     region;
3154
3155   register const Quantum
3156     *restrict p;
3157
3158   register const void
3159     *restrict r;
3160
3161   register Quantum
3162     *restrict q;
3163
3164   register ssize_t
3165     i,
3166     u;
3167
3168   register unsigned char
3169     *restrict s;
3170
3171   ssize_t
3172     v;
3173
3174   void
3175     *virtual_metacontent;
3176
3177   /*
3178     Acquire pixels.
3179   */
3180   assert(image != (const Image *) NULL);
3181   assert(image->signature == MagickSignature);
3182   assert(image->cache != (Cache) NULL);
3183   cache_info=(CacheInfo *) image->cache;
3184   assert(cache_info->signature == MagickSignature);
3185   if (cache_info->type == UndefinedCache)
3186     return((const Quantum *) NULL);
3187   region.x=x;
3188   region.y=y;
3189   region.width=columns;
3190   region.height=rows;
3191   pixels=SetPixelCacheNexusPixels(image,&region,nexus_info,exception);
3192   if (pixels == (Quantum *) NULL)
3193     return((const Quantum *) NULL);
3194   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3195     nexus_info->region.x;
3196   length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3197     nexus_info->region.width-1L;
3198   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3199   if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3200     if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3201         (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3202       {
3203         MagickBooleanType
3204           status;
3205
3206         /*
3207           Pixel request is inside cache extents.
3208         */
3209         if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3210           return(pixels);
3211         status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3212         if (status == MagickFalse)
3213           return((const Quantum *) NULL);
3214         if (cache_info->metacontent_extent != 0)
3215           {
3216             status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3217             if (status == MagickFalse)
3218               return((const Quantum *) NULL);
3219           }
3220         return(pixels);
3221       }
3222   /*
3223     Pixel request is outside cache extents.
3224   */
3225   q=pixels;
3226   s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3227   virtual_nexus=AcquirePixelCacheNexus(1);
3228   if (virtual_nexus == (NexusInfo **) NULL)
3229     {
3230       if (virtual_nexus != (NexusInfo **) NULL)
3231         virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3232       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3233         "UnableToGetCacheNexus","`%s'",image->filename);
3234       return((const Quantum *) NULL);
3235     }
3236   (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3237     sizeof(*virtual_pixel));
3238   virtual_metacontent=(void *) NULL;
3239   switch (virtual_pixel_method)
3240   {
3241     case BackgroundVirtualPixelMethod:
3242     case BlackVirtualPixelMethod:
3243     case GrayVirtualPixelMethod:
3244     case TransparentVirtualPixelMethod:
3245     case MaskVirtualPixelMethod:
3246     case WhiteVirtualPixelMethod:
3247     case EdgeVirtualPixelMethod:
3248     case CheckerTileVirtualPixelMethod:
3249     case HorizontalTileVirtualPixelMethod:
3250     case VerticalTileVirtualPixelMethod:
3251     {
3252       if (cache_info->metacontent_extent != 0)
3253         {
3254           /*
3255             Acquire a metacontent buffer.
3256           */
3257           virtual_metacontent=(void *) AcquireAlignedMemory(1,
3258             cache_info->metacontent_extent);
3259           if (virtual_metacontent == (void *) NULL)
3260             {
3261               virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3262               (void) ThrowMagickException(exception,GetMagickModule(),
3263                 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3264               return((const Quantum *) NULL);
3265             }
3266           (void) ResetMagickMemory(virtual_metacontent,0,
3267             cache_info->metacontent_extent);
3268         }
3269       switch (virtual_pixel_method)
3270       {
3271         case BlackVirtualPixelMethod:
3272         {
3273           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3274             SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3275           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3276           break;
3277         }
3278         case GrayVirtualPixelMethod:
3279         {
3280           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3281             SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,virtual_pixel);
3282           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3283           break;
3284         }
3285         case TransparentVirtualPixelMethod:
3286         {
3287           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3288             SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3289           SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3290           break;
3291         }
3292         case MaskVirtualPixelMethod:
3293         case WhiteVirtualPixelMethod:
3294         {
3295           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3296             SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3297           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3298           break;
3299         }
3300         default:
3301         {
3302           SetPixelRed(image,image->background_color.red,virtual_pixel);
3303           SetPixelGreen(image,image->background_color.green,virtual_pixel);
3304           SetPixelBlue(image,image->background_color.blue,virtual_pixel);
3305           if (image->colorspace == CMYKColorspace)
3306             SetPixelBlack(image,image->background_color.black,virtual_pixel);
3307           SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3308           break;
3309         }
3310       }
3311       break;
3312     }
3313     default:
3314       break;
3315   }
3316   for (v=0; v < (ssize_t) rows; v++)
3317   {
3318     for (u=0; u < (ssize_t) columns; u+=length)
3319     {
3320       length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3321       if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3322           (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3323           (length == 0))
3324         {
3325           MagickModulo
3326             x_modulo,
3327             y_modulo;
3328
3329           /*
3330             Transfer a single pixel.
3331           */
3332           length=(MagickSizeType) 1;
3333           switch (virtual_pixel_method)
3334           {
3335             default:
3336             {
3337               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3338                 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3339                 1UL,1UL,*virtual_nexus,exception);
3340               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3341               break;
3342             }
3343             case RandomVirtualPixelMethod:
3344             {
3345               if (cache_info->random_info == (RandomInfo *) NULL)
3346                 cache_info->random_info=AcquireRandomInfo();
3347               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3348                 RandomX(cache_info->random_info,cache_info->columns),
3349                 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3350                 *virtual_nexus,exception);
3351               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3352               break;
3353             }
3354             case DitherVirtualPixelMethod:
3355             {
3356               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3357                 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3358                 1UL,1UL,*virtual_nexus,exception);
3359               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3360               break;
3361             }
3362             case TileVirtualPixelMethod:
3363             {
3364               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3365               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3366               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3367                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3368                 exception);
3369               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3370               break;
3371             }
3372             case MirrorVirtualPixelMethod:
3373             {
3374               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3375               if ((x_modulo.quotient & 0x01) == 1L)
3376                 x_modulo.remainder=(ssize_t) cache_info->columns-
3377                   x_modulo.remainder-1L;
3378               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3379               if ((y_modulo.quotient & 0x01) == 1L)
3380                 y_modulo.remainder=(ssize_t) cache_info->rows-
3381                   y_modulo.remainder-1L;
3382               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3383                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3384                 exception);
3385               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3386               break;
3387             }
3388             case HorizontalTileEdgeVirtualPixelMethod:
3389             {
3390               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3391               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3392                 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3393                 *virtual_nexus,exception);
3394               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3395               break;
3396             }
3397             case VerticalTileEdgeVirtualPixelMethod:
3398             {
3399               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3400               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3401                 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3402                 *virtual_nexus,exception);
3403               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3404               break;
3405             }
3406             case BackgroundVirtualPixelMethod:
3407             case BlackVirtualPixelMethod:
3408             case GrayVirtualPixelMethod:
3409             case TransparentVirtualPixelMethod:
3410             case MaskVirtualPixelMethod:
3411             case WhiteVirtualPixelMethod:
3412             {
3413               p=virtual_pixel;
3414               r=virtual_metacontent;
3415               break;
3416             }
3417             case EdgeVirtualPixelMethod:
3418             case CheckerTileVirtualPixelMethod:
3419             {
3420               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3421               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3422               if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3423                 {
3424                   p=virtual_pixel;
3425                   r=virtual_metacontent;
3426                   break;
3427                 }
3428               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3429                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3430                 exception);
3431               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3432               break;
3433             }
3434             case HorizontalTileVirtualPixelMethod:
3435             {
3436               if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3437                 {
3438                   p=virtual_pixel;
3439                   r=virtual_metacontent;
3440                   break;
3441                 }
3442               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3443               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3444               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3445                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3446                 exception);
3447               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3448               break;
3449             }
3450             case VerticalTileVirtualPixelMethod:
3451             {
3452               if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3453                 {
3454                   p=virtual_pixel;
3455                   r=virtual_metacontent;
3456                   break;
3457                 }
3458               x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3459               y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3460               p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3461                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3462                 exception);
3463               r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3464               break;
3465             }
3466           }
3467           if (p == (const Quantum *) NULL)
3468             break;
3469           (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3470             sizeof(*p));
3471           q+=cache_info->number_channels;
3472           if ((s != (void *) NULL) && (r != (const void *) NULL))
3473             {
3474               (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3475               s+=cache_info->metacontent_extent;
3476             }
3477           continue;
3478         }
3479       /*
3480         Transfer a run of pixels.
3481       */
3482       p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3483         length,1UL,*virtual_nexus,exception);
3484       if (p == (const Quantum *) NULL)
3485         break;
3486       r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3487       (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3488       q+=length*cache_info->number_channels;
3489       if ((r != (void *) NULL) && (s != (const void *) NULL))
3490         {
3491           (void) memcpy(s,r,(size_t) length);
3492           s+=length*cache_info->metacontent_extent;
3493         }
3494     }
3495   }
3496   /*
3497     Free resources.
3498   */
3499   if (virtual_metacontent != (void *) NULL)
3500     virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3501   virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3502   return(pixels);
3503 }
3504 \f
3505 /*
3506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3507 %                                                                             %
3508 %                                                                             %
3509 %                                                                             %
3510 +   G e t V i r t u a l P i x e l C a c h e                                   %
3511 %                                                                             %
3512 %                                                                             %
3513 %                                                                             %
3514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3515 %
3516 %  GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3517 %  cache as defined by the geometry parameters.   A pointer to the pixels
3518 %  is returned if the pixels are transferred, otherwise a NULL is returned.
3519 %
3520 %  The format of the GetVirtualPixelCache() method is:
3521 %
3522 %      const Quantum *GetVirtualPixelCache(const Image *image,
3523 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3524 %        const ssize_t y,const size_t columns,const size_t rows,
3525 %        ExceptionInfo *exception)
3526 %
3527 %  A description of each parameter follows:
3528 %
3529 %    o image: the image.
3530 %
3531 %    o virtual_pixel_method: the virtual pixel method.
3532 %
3533 %    o x,y,columns,rows:  These values define the perimeter of a region of
3534 %      pixels.
3535 %
3536 %    o exception: return any errors or warnings in this structure.
3537 %
3538 */
3539 static const Quantum *GetVirtualPixelCache(const Image *image,
3540   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3541   const size_t columns,const size_t rows,ExceptionInfo *exception)
3542 {
3543   CacheInfo
3544     *cache_info;
3545
3546   const int
3547     id = GetOpenMPThreadId();
3548
3549   const Quantum
3550     *pixels;
3551
3552   assert(image != (const Image *) NULL);
3553   assert(image->signature == MagickSignature);
3554   assert(image->cache != (Cache) NULL);
3555   cache_info=(CacheInfo *) image->cache;
3556   assert(cache_info->signature == MagickSignature);
3557   assert(id < (int) cache_info->number_threads);
3558   pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3559     cache_info->nexus_info[id],exception);
3560   return(pixels);
3561 }
3562 \f
3563 /*
3564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3565 %                                                                             %
3566 %                                                                             %
3567 %                                                                             %
3568 %   G e t V i r t u a l P i x e l Q u e u e                                   %
3569 %                                                                             %
3570 %                                                                             %
3571 %                                                                             %
3572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3573 %
3574 %  GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3575 %  with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3576 %
3577 %  The format of the GetVirtualPixelQueue() method is:
3578 %
3579 %      const Quantum *GetVirtualPixelQueue(const Image image)
3580 %
3581 %  A description of each parameter follows:
3582 %
3583 %    o image: the image.
3584 %
3585 */
3586 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3587 {
3588   CacheInfo
3589     *cache_info;
3590
3591   const int
3592     id = GetOpenMPThreadId();
3593
3594   assert(image != (const Image *) NULL);
3595   assert(image->signature == MagickSignature);
3596   assert(image->cache != (Cache) NULL);
3597   cache_info=(CacheInfo *) image->cache;
3598   assert(cache_info->signature == MagickSignature);
3599   if (cache_info->methods.get_virtual_pixels_handler !=
3600        (GetVirtualPixelsHandler) NULL)
3601     return(cache_info->methods.get_virtual_pixels_handler(image));
3602   assert(id < (int) cache_info->number_threads);
3603   return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3604 }
3605 \f
3606 /*
3607 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3608 %                                                                             %
3609 %                                                                             %
3610 %                                                                             %
3611 %   G e t V i r t u a l P i x e l s                                           %
3612 %                                                                             %
3613 %                                                                             %
3614 %                                                                             %
3615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3616 %
3617 %  GetVirtualPixels() returns an immutable pixel region. If the
3618 %  region is successfully accessed, a pointer to it is returned, otherwise
3619 %  NULL is returned.  The returned pointer may point to a temporary working
3620 %  copy of the pixels or it may point to the original pixels in memory.
3621 %  Performance is maximized if the selected region is part of one row, or one
3622 %  or more full rows, since there is opportunity to access the pixels in-place
3623 %  (without a copy) if the image is in memory, or in a memory-mapped file.  The
3624 %  returned pointer must *never* be deallocated by the user.
3625 %
3626 %  Pixels accessed via the returned pointer represent a simple array of type
3627 %  Quantum.  If the image type is CMYK or the storage class is PseudoClass,
3628 %  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3629 %  access the meta-content (of type void) corresponding to the the
3630 %  region.
3631 %
3632 %  If you plan to modify the pixels, use GetAuthenticPixels() instead.
3633 %
3634 %  Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3635 %  safe.  In a threaded environment, use GetCacheViewVirtualPixels() or
3636 %  GetCacheViewAuthenticPixels() instead.
3637 %
3638 %  The format of the GetVirtualPixels() method is:
3639 %
3640 %      const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3641 %        const ssize_t y,const size_t columns,const size_t rows,
3642 %        ExceptionInfo *exception)
3643 %
3644 %  A description of each parameter follows:
3645 %
3646 %    o image: the image.
3647 %
3648 %    o x,y,columns,rows:  These values define the perimeter of a region of
3649 %      pixels.
3650 %
3651 %    o exception: return any errors or warnings in this structure.
3652 %
3653 */
3654 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3655   const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3656   ExceptionInfo *exception)
3657 {
3658   CacheInfo
3659     *cache_info;
3660
3661   const int
3662     id = GetOpenMPThreadId();
3663
3664   const Quantum
3665     *pixels;
3666
3667   assert(image != (const Image *) NULL);
3668   assert(image->signature == MagickSignature);
3669   assert(image->cache != (Cache) NULL);
3670   cache_info=(CacheInfo *) image->cache;
3671   assert(cache_info->signature == MagickSignature);
3672   if (cache_info->methods.get_virtual_pixel_handler !=
3673        (GetVirtualPixelHandler) NULL)
3674     return(cache_info->methods.get_virtual_pixel_handler(image,
3675       GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3676   assert(id < (int) cache_info->number_threads);
3677   pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3678     columns,rows,cache_info->nexus_info[id],exception);
3679   return(pixels);
3680 }
3681 \f
3682 /*
3683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3684 %                                                                             %
3685 %                                                                             %
3686 %                                                                             %
3687 +   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                         %
3688 %                                                                             %
3689 %                                                                             %
3690 %                                                                             %
3691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3692 %
3693 %  GetVirtualPixelsCache() returns the pixels associated corresponding with the
3694 %  last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3695 %
3696 %  The format of the GetVirtualPixelsCache() method is:
3697 %
3698 %      Quantum *GetVirtualPixelsCache(const Image *image)
3699 %
3700 %  A description of each parameter follows:
3701 %
3702 %    o image: the image.
3703 %
3704 */
3705 static const Quantum *GetVirtualPixelsCache(const Image *image)
3706 {
3707   CacheInfo
3708     *cache_info;
3709
3710   const int
3711     id = GetOpenMPThreadId();
3712
3713   assert(image != (const Image *) NULL);
3714   assert(image->signature == MagickSignature);
3715   assert(image->cache != (Cache) NULL);
3716   cache_info=(CacheInfo *) image->cache;
3717   assert(cache_info->signature == MagickSignature);
3718   assert(id < (int) cache_info->number_threads);
3719   return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3720 }
3721 \f
3722 /*
3723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3724 %                                                                             %
3725 %                                                                             %
3726 %                                                                             %
3727 +   G e t V i r t u a l P i x e l s N e x u s                                 %
3728 %                                                                             %
3729 %                                                                             %
3730 %                                                                             %
3731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3732 %
3733 %  GetVirtualPixelsNexus() returns the pixels associated with the specified
3734 %  cache nexus.
3735 %
3736 %  The format of the GetVirtualPixelsNexus() method is:
3737 %
3738 %      const Quantum *GetVirtualPixelsNexus(const Cache cache,
3739 %        NexusInfo *nexus_info)
3740 %
3741 %  A description of each parameter follows:
3742 %
3743 %    o cache: the pixel cache.
3744 %
3745 %    o nexus_info: the cache nexus to return the colormap pixels.
3746 %
3747 */
3748 MagickExport const Quantum *GetVirtualPixelsNexus(const Cache cache,
3749   NexusInfo *nexus_info)
3750 {
3751   CacheInfo
3752     *cache_info;
3753
3754   assert(cache != (Cache) NULL);
3755   cache_info=(CacheInfo *) cache;
3756   assert(cache_info->signature == MagickSignature);
3757   if (cache_info->storage_class == UndefinedClass)
3758     return((Quantum *) NULL);
3759   return((const Quantum *) nexus_info->pixels);
3760 }
3761 \f
3762 /*
3763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3764 %                                                                             %
3765 %                                                                             %
3766 %                                                                             %
3767 +   M a s k P i x e l C a c h e N e x u s                                     %
3768 %                                                                             %
3769 %                                                                             %
3770 %                                                                             %
3771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3772 %
3773 %  MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3774 %  The method returns MagickTrue if the pixel region is masked, otherwise
3775 %  MagickFalse.
3776 %
3777 %  The format of the MaskPixelCacheNexus() method is:
3778 %
3779 %      MagickBooleanType MaskPixelCacheNexus(Image *image,
3780 %        NexusInfo *nexus_info,ExceptionInfo *exception)
3781 %
3782 %  A description of each parameter follows:
3783 %
3784 %    o image: the image.
3785 %
3786 %    o nexus_info: the cache nexus to clip.
3787 %
3788 %    o exception: return any errors or warnings in this structure.
3789 %
3790 */
3791
3792 static inline void MagickPixelCompositeMask(const PixelInfo *p,
3793   const MagickRealType alpha,const PixelInfo *q,
3794   const MagickRealType beta,PixelInfo *composite)
3795 {
3796   MagickRealType
3797     gamma;
3798
3799   if (alpha == TransparentAlpha)
3800     {
3801       *composite=(*q);
3802       return;
3803     }
3804   gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3805   gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3806   composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3807   composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3808   composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3809   if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3810     composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
3811 }
3812
3813 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3814   ExceptionInfo *exception)
3815 {
3816   CacheInfo
3817     *cache_info;
3818
3819   PixelInfo
3820     alpha,
3821     beta;
3822
3823   MagickSizeType
3824     number_pixels;
3825
3826   NexusInfo
3827     **clip_nexus,
3828     **image_nexus;
3829
3830   register const Quantum
3831     *restrict p,
3832     *restrict r;
3833
3834   register Quantum
3835     *restrict q;
3836
3837   register ssize_t
3838     i;
3839
3840   /*
3841     Apply clip mask.
3842   */
3843   if (image->debug != MagickFalse)
3844     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3845   if (image->mask == (Image *) NULL)
3846     return(MagickFalse);
3847   cache_info=(CacheInfo *) image->cache;
3848   if (cache_info == (Cache) NULL)
3849     return(MagickFalse);
3850   image_nexus=AcquirePixelCacheNexus(1);
3851   clip_nexus=AcquirePixelCacheNexus(1);
3852   if ((image_nexus == (NexusInfo **) NULL) ||
3853       (clip_nexus == (NexusInfo **) NULL))
3854     ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3855   p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3856     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3857     nexus_info->region.height,image_nexus[0],exception);
3858   q=nexus_info->pixels;
3859   r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3860     nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3861     nexus_info->region.height,clip_nexus[0],&image->exception);
3862   GetPixelInfo(image,&alpha);
3863   GetPixelInfo(image,&beta);
3864   number_pixels=(MagickSizeType) nexus_info->region.width*
3865     nexus_info->region.height;
3866   for (i=0; i < (ssize_t) number_pixels; i++)
3867   {
3868     if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
3869       break;
3870     SetPixelInfo(image,p,&alpha);
3871     SetPixelInfo(image,q,&beta);
3872     MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3873       &alpha,alpha.alpha,&beta);
3874     SetPixelRed(image,ClampToQuantum(beta.red),q);
3875     SetPixelGreen(image,ClampToQuantum(beta.green),q);
3876     SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3877     if (cache_info->colorspace == CMYKColorspace)
3878       SetPixelBlack(image,ClampToQuantum(beta.black),q);
3879     SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
3880     p++;
3881     q++;
3882     r++;
3883   }
3884   clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3885   image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3886   if (i < (ssize_t) number_pixels)
3887     return(MagickFalse);
3888   return(MagickTrue);
3889 }
3890 \f
3891 /*
3892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3893 %                                                                             %
3894 %                                                                             %
3895 %                                                                             %
3896 +   O p e n P i x e l C a c h e                                               %
3897 %                                                                             %
3898 %                                                                             %
3899 %                                                                             %
3900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3901 %
3902 %  OpenPixelCache() allocates the pixel cache.  This includes defining the cache
3903 %  dimensions, allocating space for the image pixels and optionally the
3904 %  metacontent, and memory mapping the cache if it is disk based.  The cache
3905 %  nexus array is initialized as well.
3906 %
3907 %  The format of the OpenPixelCache() method is:
3908 %
3909 %      MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3910 %        ExceptionInfo *exception)
3911 %
3912 %  A description of each parameter follows:
3913 %
3914 %    o image: the image.
3915 %
3916 %    o mode: ReadMode, WriteMode, or IOMode.
3917 %
3918 %    o exception: return any errors or warnings in this structure.
3919 %
3920 */
3921
3922 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3923 {
3924   cache_info->mapped=MagickFalse;
3925   cache_info->pixels=(Quantum *) AcquireAlignedMemory(1,(size_t)
3926     cache_info->length);
3927   if (cache_info->pixels == (Quantum *) NULL)
3928     {
3929       cache_info->mapped=MagickTrue;
3930       cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3931         cache_info->length);
3932     }
3933 }
3934
3935 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3936 {
3937   CacheInfo
3938     *cache_info;
3939
3940   MagickOffsetType
3941     count,
3942     extent,
3943     offset;
3944
3945   cache_info=(CacheInfo *) image->cache;
3946   if (image->debug != MagickFalse)
3947     {
3948       char
3949         format[MaxTextExtent],
3950         message[MaxTextExtent];
3951
3952       (void) FormatMagickSize(length,MagickFalse,format);
3953       (void) FormatLocaleString(message,MaxTextExtent,
3954         "extend %s (%s[%d], disk, %s)",cache_info->filename,
3955         cache_info->cache_filename,cache_info->file,format);
3956       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3957     }
3958   if (length != (MagickSizeType) ((MagickOffsetType) length))
3959     return(MagickFalse);
3960   extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3961   if (extent < 0)
3962     return(MagickFalse);
3963   if ((MagickSizeType) extent >= length)
3964     return(MagickTrue);
3965   offset=(MagickOffsetType) length-1;
3966   count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3967   return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3968 }
3969
3970 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3971   ExceptionInfo *exception)
3972 {
3973   CacheInfo
3974     *cache_info,
3975     source_info;
3976
3977   char
3978     format[MaxTextExtent],
3979     message[MaxTextExtent];
3980
3981   MagickBooleanType
3982     status;
3983
3984   MagickSizeType
3985     length,
3986     number_pixels;
3987
3988   size_t
3989     columns,
3990     packet_size;
3991
3992   assert(image != (const Image *) NULL);
3993   assert(image->signature == MagickSignature);
3994   assert(image->cache != (Cache) NULL);
3995   if (image->debug != MagickFalse)
3996     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3997   if ((image->columns == 0) || (image->rows == 0))
3998     ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3999   StandardPixelChannelMap(image);
4000   cache_info=(CacheInfo *) image->cache;
4001   assert(cache_info->signature == MagickSignature);
4002   source_info=(*cache_info);
4003   source_info.file=(-1);
4004   (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4005     image->filename,(double) GetImageIndexInList(image));
4006   cache_info->storage_class=image->storage_class;
4007   cache_info->colorspace=image->colorspace;
4008   cache_info->matte=image->matte;
4009   cache_info->rows=image->rows;
4010   cache_info->columns=image->columns;
4011   cache_info->number_channels=GetPixelChannels(image);
4012   cache_info->metacontent_extent=image->metacontent_extent;
4013   cache_info->mode=mode;
4014   if (image->ping != MagickFalse)
4015     {
4016       cache_info->type=PingCache;
4017       cache_info->pixels=(Quantum *) NULL;
4018       cache_info->metacontent=(void *) NULL;
4019       cache_info->length=0;
4020       return(MagickTrue);
4021     }
4022   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4023   packet_size=cache_info->number_channels*sizeof(Quantum);
4024   if (image->metacontent_extent != 0)
4025     packet_size+=cache_info->metacontent_extent;
4026   length=number_pixels*packet_size;
4027   columns=(size_t) (length/cache_info->rows/packet_size);
4028   if (cache_info->columns != columns)
4029     ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4030       image->filename);
4031   cache_info->length=length;
4032   if ((cache_info->type != UndefinedCache) &&
4033       (cache_info->columns <= source_info.columns) &&
4034       (cache_info->rows <= source_info.rows) &&
4035       (cache_info->number_channels <= source_info.number_channels) &&
4036       (cache_info->metacontent_extent <= source_info.metacontent_extent))
4037     {
4038       /*
4039         Inline pixel cache clone optimization.
4040       */
4041       if ((cache_info->columns == source_info.columns) &&
4042           (cache_info->rows == source_info.rows) &&
4043           (cache_info->number_channels == source_info.number_channels) &&
4044           (cache_info->metacontent_extent == source_info.metacontent_extent))
4045         return(MagickTrue);
4046       return(ClonePixelCachePixels(cache_info,&source_info,exception));
4047     }
4048   status=AcquireMagickResource(AreaResource,cache_info->length);
4049   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4050     cache_info->metacontent_extent);
4051   if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4052     {
4053       status=AcquireMagickResource(MemoryResource,cache_info->length);
4054       if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4055           (cache_info->type == MemoryCache))
4056         {
4057           AllocatePixelCachePixels(cache_info);
4058           if (cache_info->pixels == (Quantum *) NULL)
4059             cache_info->pixels=source_info.pixels;
4060           else
4061             {
4062               /*
4063                 Create memory pixel cache.
4064               */
4065               status=MagickTrue;
4066               if (image->debug != MagickFalse)
4067                 {
4068                   (void) FormatMagickSize(cache_info->length,MagickTrue,
4069                     format);
4070                   (void) FormatLocaleString(message,MaxTextExtent,
4071                     "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4072                     cache_info->filename,cache_info->mapped != MagickFalse ?
4073                     "anonymous" : "heap",(double) cache_info->columns,(double)
4074                     cache_info->rows,(double) cache_info->number_channels,
4075                     format);
4076                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4077                     message);
4078                 }
4079               cache_info->type=MemoryCache;
4080               cache_info->metacontent=(void *) NULL;
4081               if (cache_info->metacontent_extent != 0)
4082                 cache_info->metacontent=(void *) (cache_info->pixels+
4083                   number_pixels*cache_info->number_channels);
4084               if (source_info.storage_class != UndefinedClass)
4085                 {
4086                   status=ClonePixelCachePixels(cache_info,&source_info,
4087                     exception);
4088                   RelinquishPixelCachePixels(&source_info);
4089                 }
4090               return(status);
4091             }
4092         }
4093       RelinquishMagickResource(MemoryResource,cache_info->length);
4094     }
4095   /*
4096     Create pixel cache on disk.
4097   */
4098   status=AcquireMagickResource(DiskResource,cache_info->length);
4099   if (status == MagickFalse)
4100     {
4101       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4102         "CacheResourcesExhausted","`%s'",image->filename);
4103       return(MagickFalse);
4104     }
4105   if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4106     {
4107       RelinquishMagickResource(DiskResource,cache_info->length);
4108       ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4109         image->filename);
4110       return(MagickFalse);
4111     }
4112   status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4113     cache_info->length);
4114   if (status == MagickFalse)
4115     {
4116       ThrowFileException(exception,CacheError,"UnableToExtendCache",
4117         image->filename);
4118       return(MagickFalse);
4119     }
4120   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4121     cache_info->metacontent_extent);
4122   status=AcquireMagickResource(AreaResource,cache_info->length);
4123   if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4124     cache_info->type=DiskCache;
4125   else
4126     {
4127       status=AcquireMagickResource(MapResource,cache_info->length);
4128       if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4129           (cache_info->type != MemoryCache))
4130         cache_info->type=DiskCache;
4131       else
4132         {
4133           cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4134             cache_info->offset,(size_t) cache_info->length);
4135           if (cache_info->pixels == (Quantum *) NULL)
4136             {
4137               cache_info->type=DiskCache;
4138               cache_info->pixels=source_info.pixels;
4139             }
4140           else
4141             {
4142               /*
4143                 Create file-backed memory-mapped pixel cache.
4144               */
4145               status=MagickTrue;
4146               (void) ClosePixelCacheOnDisk(cache_info);
4147               cache_info->type=MapCache;
4148               cache_info->mapped=MagickTrue;
4149               cache_info->metacontent=(void *) NULL;
4150               if (cache_info->metacontent_extent != 0)
4151                 cache_info->metacontent=(void *) (cache_info->pixels+
4152                   number_pixels*cache_info->number_channels);
4153               if (source_info.storage_class != UndefinedClass)
4154                 {
4155                   status=ClonePixelCachePixels(cache_info,&source_info,
4156                     exception);
4157                   RelinquishPixelCachePixels(&source_info);
4158                 }
4159               if (image->debug != MagickFalse)
4160                 {
4161                   (void) FormatMagickSize(cache_info->length,MagickTrue,
4162                     format);
4163                   (void) FormatLocaleString(message,MaxTextExtent,
4164                     "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4165                     cache_info->filename,cache_info->cache_filename,
4166                     cache_info->file,(double) cache_info->columns,(double)
4167                     cache_info->rows,(double) cache_info->number_channels,
4168                     format);
4169                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4170                     message);
4171                 }
4172               return(status);
4173             }
4174         }
4175       RelinquishMagickResource(MapResource,cache_info->length);
4176     }
4177   status=MagickTrue;
4178   if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4179     {
4180       status=ClonePixelCachePixels(cache_info,&source_info,exception);
4181       RelinquishPixelCachePixels(&source_info);
4182     }
4183   if (image->debug != MagickFalse)
4184     {
4185       (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4186       (void) FormatLocaleString(message,MaxTextExtent,
4187         "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4188         cache_info->cache_filename,cache_info->file,(double)
4189         cache_info->columns,(double) cache_info->rows,(double)
4190         cache_info->number_channels,format);
4191       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4192     }
4193   return(status);
4194 }
4195 \f
4196 /*
4197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4198 %                                                                             %
4199 %                                                                             %
4200 %                                                                             %
4201 +   P e r s i s t P i x e l C a c h e                                         %
4202 %                                                                             %
4203 %                                                                             %
4204 %                                                                             %
4205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4206 %
4207 %  PersistPixelCache() attaches to or initializes a persistent pixel cache.  A
4208 %  persistent pixel cache is one that resides on disk and is not destroyed
4209 %  when the program exits.
4210 %
4211 %  The format of the PersistPixelCache() method is:
4212 %
4213 %      MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4214 %        const MagickBooleanType attach,MagickOffsetType *offset,
4215 %        ExceptionInfo *exception)
4216 %
4217 %  A description of each parameter follows:
4218 %
4219 %    o image: the image.
4220 %
4221 %    o filename: the persistent pixel cache filename.
4222 %
4223 %    o attach: A value other than zero initializes the persistent pixel cache.
4224 %
4225 %    o initialize: A value other than zero initializes the persistent pixel
4226 %      cache.
4227 %
4228 %    o offset: the offset in the persistent cache to store pixels.
4229 %
4230 %    o exception: return any errors or warnings in this structure.
4231 %
4232 */
4233 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4234   const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4235   ExceptionInfo *exception)
4236 {
4237   CacheInfo
4238     *cache_info,
4239     *clone_info;
4240
4241   Image
4242     clone_image;
4243
4244   MagickBooleanType
4245     status;
4246
4247   ssize_t
4248     page_size;
4249
4250   assert(image != (Image *) NULL);
4251   assert(image->signature == MagickSignature);
4252   if (image->debug != MagickFalse)
4253     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4254   assert(image->cache != (void *) NULL);
4255   assert(filename != (const char *) NULL);
4256   assert(offset != (MagickOffsetType *) NULL);
4257   page_size=GetMagickPageSize();
4258   cache_info=(CacheInfo *) image->cache;
4259   assert(cache_info->signature == MagickSignature);
4260   if (attach != MagickFalse)
4261     {
4262       /*
4263         Attach existing persistent pixel cache.
4264       */
4265       if (image->debug != MagickFalse)
4266         (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4267           "attach persistent cache");
4268       (void) CopyMagickString(cache_info->cache_filename,filename,
4269         MaxTextExtent);
4270       cache_info->type=DiskCache;
4271       cache_info->offset=(*offset);
4272       if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4273         return(MagickFalse);
4274       *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4275       return(MagickTrue);
4276     }
4277   if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4278       (cache_info->reference_count == 1))
4279     {
4280       LockSemaphoreInfo(cache_info->semaphore);
4281       if ((cache_info->mode != ReadMode) && (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 }