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