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