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