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