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 %                                                                             %
1143 %   G e t A u t h e n t i c M e t a c o n t e n t                             %
1144 %                                                                             %
1145 %                                                                             %
1146 %                                                                             %
1147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1148 %
1149 %  GetAuthenticMetacontent() returns the authentic metacontent corresponding
1150 %  with the last call to QueueAuthenticPixels() or GetVirtualPixels().  NULL is
1151 %  returned if the associated pixels are not available.
1152 %
1153 %  The format of the GetAuthenticMetacontent() method is:
1154 %
1155 %      void *GetAuthenticMetacontent(const Image *image)
1156 %
1157 %  A description of each parameter follows:
1158 %
1159 %    o image: the image.
1160 %
1161 */
GetAuthenticMetacontent(const Image * image)1162 MagickExport void *GetAuthenticMetacontent(const Image *image)
1163 {
1164   CacheInfo
1165     *magick_restrict cache_info;
1166 
1167   const int
1168     id = GetOpenMPThreadId();
1169 
1170   assert(image != (const Image *) NULL);
1171   assert(image->signature == MagickCoreSignature);
1172   assert(image->cache != (Cache) NULL);
1173   cache_info=(CacheInfo *) image->cache;
1174   assert(cache_info->signature == MagickCoreSignature);
1175   if (cache_info->methods.get_authentic_metacontent_from_handler !=
1176       (GetAuthenticMetacontentFromHandler) NULL)
1177     {
1178       void
1179         *metacontent;
1180 
1181       metacontent=cache_info->methods.
1182         get_authentic_metacontent_from_handler(image);
1183       return(metacontent);
1184     }
1185   assert(id < (int) cache_info->number_threads);
1186   return(cache_info->nexus_info[id]->metacontent);
1187 }
1188 
1189 /*
1190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191 %                                                                             %
1192 %                                                                             %
1193 %                                                                             %
1194 +   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           %
1195 %                                                                             %
1196 %                                                                             %
1197 %                                                                             %
1198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199 %
1200 %  GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1201 %  with the last call to QueueAuthenticPixelsCache() or
1202 %  GetAuthenticPixelsCache().
1203 %
1204 %  The format of the GetAuthenticMetacontentFromCache() method is:
1205 %
1206 %      void *GetAuthenticMetacontentFromCache(const Image *image)
1207 %
1208 %  A description of each parameter follows:
1209 %
1210 %    o image: the image.
1211 %
1212 */
GetAuthenticMetacontentFromCache(const Image * image)1213 static void *GetAuthenticMetacontentFromCache(const Image *image)
1214 {
1215   CacheInfo
1216     *magick_restrict cache_info;
1217 
1218   const int
1219     id = GetOpenMPThreadId();
1220 
1221   assert(image != (const Image *) NULL);
1222   assert(image->signature == MagickCoreSignature);
1223   assert(image->cache != (Cache) NULL);
1224   cache_info=(CacheInfo *) image->cache;
1225   assert(cache_info->signature == MagickCoreSignature);
1226   assert(id < (int) cache_info->number_threads);
1227   return(cache_info->nexus_info[id]->metacontent);
1228 }
1229 
1230 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1231 /*
1232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1233 %                                                                             %
1234 %                                                                             %
1235 %                                                                             %
1236 +   G e t A u t h e n t i c O p e n C L B u f f e r                           %
1237 %                                                                             %
1238 %                                                                             %
1239 %                                                                             %
1240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1241 %
1242 %  GetAuthenticOpenCLBuffer() returns an OpenCL buffer used to execute OpenCL
1243 %  operations.
1244 %
1245 %  The format of the GetAuthenticOpenCLBuffer() method is:
1246 %
1247 %      cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1248 %        MagickCLDevice device,ExceptionInfo *exception)
1249 %
1250 %  A description of each parameter follows:
1251 %
1252 %    o image: the image.
1253 %
1254 %    o device: the device to use.
1255 %
1256 %    o exception: return any errors or warnings in this structure.
1257 %
1258 */
GetAuthenticOpenCLBuffer(const Image * image,MagickCLDevice device,ExceptionInfo * exception)1259 MagickPrivate cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1260   MagickCLDevice device,ExceptionInfo *exception)
1261 {
1262   CacheInfo
1263     *magick_restrict cache_info;
1264 
1265   assert(image != (const Image *) NULL);
1266   assert(device != (const MagickCLDevice) NULL);
1267   cache_info=(CacheInfo *) image->cache;
1268   if ((cache_info->type == UndefinedCache) || (cache_info->reference_count > 1))
1269     {
1270       SyncImagePixelCache((Image *) image,exception);
1271       cache_info=(CacheInfo *) image->cache;
1272     }
1273   if ((cache_info->type != MemoryCache) || (cache_info->mapped != MagickFalse))
1274     return((cl_mem) NULL);
1275   LockSemaphoreInfo(cache_info->semaphore);
1276   if ((cache_info->opencl != (MagickCLCacheInfo) NULL) &&
1277       (cache_info->opencl->device->context != device->context))
1278     cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
1279   if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1280     {
1281       assert(cache_info->pixels != (Quantum *) NULL);
1282       cache_info->opencl=AcquireMagickCLCacheInfo(device,cache_info->pixels,
1283         cache_info->length);
1284     }
1285   if (cache_info->opencl != (MagickCLCacheInfo) NULL)
1286     RetainOpenCLMemObject(cache_info->opencl->buffer);
1287   UnlockSemaphoreInfo(cache_info->semaphore);
1288   if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1289     return((cl_mem) NULL);
1290   assert(cache_info->opencl->pixels == cache_info->pixels);
1291   return(cache_info->opencl->buffer);
1292 }
1293 #endif
1294 
1295 /*
1296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1297 %                                                                             %
1298 %                                                                             %
1299 %                                                                             %
1300 +   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                     %
1301 %                                                                             %
1302 %                                                                             %
1303 %                                                                             %
1304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305 %
1306 %  GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1307 %  disk pixel cache as defined by the geometry parameters.   A pointer to the
1308 %  pixels is returned if the pixels are transferred, otherwise a NULL is
1309 %  returned.
1310 %
1311 %  The format of the GetAuthenticPixelCacheNexus() method is:
1312 %
1313 %      Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1314 %        const ssize_t y,const size_t columns,const size_t rows,
1315 %        NexusInfo *nexus_info,ExceptionInfo *exception)
1316 %
1317 %  A description of each parameter follows:
1318 %
1319 %    o image: the image.
1320 %
1321 %    o x,y,columns,rows:  These values define the perimeter of a region of
1322 %      pixels.
1323 %
1324 %    o nexus_info: the cache nexus to return.
1325 %
1326 %    o exception: return any errors or warnings in this structure.
1327 %
1328 */
1329 
GetAuthenticPixelCacheNexus(Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,NexusInfo * nexus_info,ExceptionInfo * exception)1330 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1331   const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1332   ExceptionInfo *exception)
1333 {
1334   CacheInfo
1335     *magick_restrict cache_info;
1336 
1337   Quantum
1338     *magick_restrict pixels;
1339 
1340   /*
1341     Transfer pixels from the cache.
1342   */
1343   assert(image != (Image *) NULL);
1344   assert(image->signature == MagickCoreSignature);
1345   pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1346     nexus_info,exception);
1347   if (pixels == (Quantum *) NULL)
1348     return((Quantum *) NULL);
1349   cache_info=(CacheInfo *) image->cache;
1350   assert(cache_info->signature == MagickCoreSignature);
1351   if (nexus_info->authentic_pixel_cache != MagickFalse)
1352     return(pixels);
1353   if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1354     return((Quantum *) NULL);
1355   if (cache_info->metacontent_extent != 0)
1356     if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1357       return((Quantum *) NULL);
1358   return(pixels);
1359 }
1360 
1361 /*
1362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1363 %                                                                             %
1364 %                                                                             %
1365 %                                                                             %
1366 +   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                     %
1367 %                                                                             %
1368 %                                                                             %
1369 %                                                                             %
1370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371 %
1372 %  GetAuthenticPixelsFromCache() returns the pixels associated with the last
1373 %  call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1374 %
1375 %  The format of the GetAuthenticPixelsFromCache() method is:
1376 %
1377 %      Quantum *GetAuthenticPixelsFromCache(const Image image)
1378 %
1379 %  A description of each parameter follows:
1380 %
1381 %    o image: the image.
1382 %
1383 */
GetAuthenticPixelsFromCache(const Image * image)1384 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1385 {
1386   CacheInfo
1387     *magick_restrict cache_info;
1388 
1389   const int
1390     id = GetOpenMPThreadId();
1391 
1392   assert(image != (const Image *) NULL);
1393   assert(image->signature == MagickCoreSignature);
1394   assert(image->cache != (Cache) NULL);
1395   cache_info=(CacheInfo *) image->cache;
1396   assert(cache_info->signature == MagickCoreSignature);
1397   assert(id < (int) cache_info->number_threads);
1398   return(cache_info->nexus_info[id]->pixels);
1399 }
1400 
1401 /*
1402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1403 %                                                                             %
1404 %                                                                             %
1405 %                                                                             %
1406 %   G e t A u t h e n t i c P i x e l Q u e u e                               %
1407 %                                                                             %
1408 %                                                                             %
1409 %                                                                             %
1410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1411 %
1412 %  GetAuthenticPixelQueue() returns the authentic pixels associated
1413 %  corresponding with the last call to QueueAuthenticPixels() or
1414 %  GetAuthenticPixels().
1415 %
1416 %  The format of the GetAuthenticPixelQueue() method is:
1417 %
1418 %      Quantum *GetAuthenticPixelQueue(const Image image)
1419 %
1420 %  A description of each parameter follows:
1421 %
1422 %    o image: the image.
1423 %
1424 */
GetAuthenticPixelQueue(const Image * image)1425 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1426 {
1427   CacheInfo
1428     *magick_restrict cache_info;
1429 
1430   const int
1431     id = GetOpenMPThreadId();
1432 
1433   assert(image != (const Image *) NULL);
1434   assert(image->signature == MagickCoreSignature);
1435   assert(image->cache != (Cache) NULL);
1436   cache_info=(CacheInfo *) image->cache;
1437   assert(cache_info->signature == MagickCoreSignature);
1438   if (cache_info->methods.get_authentic_pixels_from_handler !=
1439        (GetAuthenticPixelsFromHandler) NULL)
1440     return(cache_info->methods.get_authentic_pixels_from_handler(image));
1441   assert(id < (int) cache_info->number_threads);
1442   return(cache_info->nexus_info[id]->pixels);
1443 }
1444 
1445 /*
1446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1447 %                                                                             %
1448 %                                                                             %
1449 %                                                                             %
1450 %   G e t A u t h e n t i c P i x e l s                                       %
1451 %                                                                             %
1452 %                                                                             %
1453 %                                                                             %
1454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1455 %
1456 %  GetAuthenticPixels() obtains a pixel region for read/write access. If the
1457 %  region is successfully accessed, a pointer to a Quantum array
1458 %  representing the region is returned, otherwise NULL is returned.
1459 %
1460 %  The returned pointer may point to a temporary working copy of the pixels
1461 %  or it may point to the original pixels in memory. Performance is maximized
1462 %  if the selected region is part of one row, or one or more full rows, since
1463 %  then there is opportunity to access the pixels in-place (without a copy)
1464 %  if the image is in memory, or in a memory-mapped file. The returned pointer
1465 %  must *never* be deallocated by the user.
1466 %
1467 %  Pixels accessed via the returned pointer represent a simple array of type
1468 %  Quantum.  If the image has corresponding metacontent,call
1469 %  GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1470 %  meta-content corresponding to the region.  Once the Quantum array has
1471 %  been updated, the changes must be saved back to the underlying image using
1472 %  SyncAuthenticPixels() or they may be lost.
1473 %
1474 %  The format of the GetAuthenticPixels() method is:
1475 %
1476 %      Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1477 %        const ssize_t y,const size_t columns,const size_t rows,
1478 %        ExceptionInfo *exception)
1479 %
1480 %  A description of each parameter follows:
1481 %
1482 %    o image: the image.
1483 %
1484 %    o x,y,columns,rows:  These values define the perimeter of a region of
1485 %      pixels.
1486 %
1487 %    o exception: return any errors or warnings in this structure.
1488 %
1489 */
GetAuthenticPixels(Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,ExceptionInfo * exception)1490 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1491   const ssize_t y,const size_t columns,const size_t rows,
1492   ExceptionInfo *exception)
1493 {
1494   CacheInfo
1495     *magick_restrict cache_info;
1496 
1497   const int
1498     id = GetOpenMPThreadId();
1499 
1500   Quantum
1501     *pixels;
1502 
1503   assert(image != (Image *) NULL);
1504   assert(image->signature == MagickCoreSignature);
1505   assert(image->cache != (Cache) NULL);
1506   cache_info=(CacheInfo *) image->cache;
1507   assert(cache_info->signature == MagickCoreSignature);
1508   if (cache_info->methods.get_authentic_pixels_handler !=
1509       (GetAuthenticPixelsHandler) NULL)
1510     {
1511       pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1512         rows,exception);
1513       return(pixels);
1514     }
1515   assert(id < (int) cache_info->number_threads);
1516   pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1517     cache_info->nexus_info[id],exception);
1518   return(pixels);
1519 }
1520 
1521 /*
1522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1523 %                                                                             %
1524 %                                                                             %
1525 %                                                                             %
1526 +   G e t A u t h e n t i c P i x e l s C a c h e                             %
1527 %                                                                             %
1528 %                                                                             %
1529 %                                                                             %
1530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1531 %
1532 %  GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1533 %  as defined by the geometry parameters.   A pointer to the pixels is returned
1534 %  if the pixels are transferred, otherwise a NULL is returned.
1535 %
1536 %  The format of the GetAuthenticPixelsCache() method is:
1537 %
1538 %      Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1539 %        const ssize_t y,const size_t columns,const size_t rows,
1540 %        ExceptionInfo *exception)
1541 %
1542 %  A description of each parameter follows:
1543 %
1544 %    o image: the image.
1545 %
1546 %    o x,y,columns,rows:  These values define the perimeter of a region of
1547 %      pixels.
1548 %
1549 %    o exception: return any errors or warnings in this structure.
1550 %
1551 */
GetAuthenticPixelsCache(Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,ExceptionInfo * exception)1552 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1553   const ssize_t y,const size_t columns,const size_t rows,
1554   ExceptionInfo *exception)
1555 {
1556   CacheInfo
1557     *magick_restrict cache_info;
1558 
1559   const int
1560     id = GetOpenMPThreadId();
1561 
1562   Quantum
1563     *magick_restrict pixels;
1564 
1565   assert(image != (const Image *) NULL);
1566   assert(image->signature == MagickCoreSignature);
1567   assert(image->cache != (Cache) NULL);
1568   cache_info=(CacheInfo *) image->cache;
1569   if (cache_info == (Cache) NULL)
1570     return((Quantum *) NULL);
1571   assert(cache_info->signature == MagickCoreSignature);
1572   assert(id < (int) cache_info->number_threads);
1573   pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1574     cache_info->nexus_info[id],exception);
1575   return(pixels);
1576 }
1577 
1578 /*
1579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1580 %                                                                             %
1581 %                                                                             %
1582 %                                                                             %
1583 +   G e t I m a g e E x t e n t                                               %
1584 %                                                                             %
1585 %                                                                             %
1586 %                                                                             %
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588 %
1589 %  GetImageExtent() returns the extent of the pixels associated corresponding
1590 %  with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1591 %
1592 %  The format of the GetImageExtent() method is:
1593 %
1594 %      MagickSizeType GetImageExtent(const Image *image)
1595 %
1596 %  A description of each parameter follows:
1597 %
1598 %    o image: the image.
1599 %
1600 */
GetImageExtent(const Image * image)1601 MagickExport MagickSizeType GetImageExtent(const Image *image)
1602 {
1603   CacheInfo
1604     *magick_restrict cache_info;
1605 
1606   const int
1607     id = GetOpenMPThreadId();
1608 
1609   assert(image != (Image *) NULL);
1610   assert(image->signature == MagickCoreSignature);
1611   if (image->debug != MagickFalse)
1612     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1613   assert(image->cache != (Cache) NULL);
1614   cache_info=(CacheInfo *) image->cache;
1615   assert(cache_info->signature == MagickCoreSignature);
1616   assert(id < (int) cache_info->number_threads);
1617   return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1618 }
1619 
1620 /*
1621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1622 %                                                                             %
1623 %                                                                             %
1624 %                                                                             %
1625 +   G e t I m a g e P i x e l C a c h e                                       %
1626 %                                                                             %
1627 %                                                                             %
1628 %                                                                             %
1629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630 %
1631 %  GetImagePixelCache() ensures that there is only a single reference to the
1632 %  pixel cache to be modified, updating the provided cache pointer to point to
1633 %  a clone of the original pixel cache if necessary.
1634 %
1635 %  The format of the GetImagePixelCache method is:
1636 %
1637 %      Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1638 %        ExceptionInfo *exception)
1639 %
1640 %  A description of each parameter follows:
1641 %
1642 %    o image: the image.
1643 %
1644 %    o clone: any value other than MagickFalse clones the cache pixels.
1645 %
1646 %    o exception: return any errors or warnings in this structure.
1647 %
1648 */
1649 
ValidatePixelCacheMorphology(const Image * magick_restrict image)1650 static inline MagickBooleanType ValidatePixelCacheMorphology(
1651   const Image *magick_restrict image)
1652 {
1653   const CacheInfo
1654     *magick_restrict cache_info;
1655 
1656   const PixelChannelMap
1657     *magick_restrict p,
1658     *magick_restrict q;
1659 
1660   /*
1661     Does the image match the pixel cache morphology?
1662   */
1663   cache_info=(CacheInfo *) image->cache;
1664   p=image->channel_map;
1665   q=cache_info->channel_map;
1666   if ((image->storage_class != cache_info->storage_class) ||
1667       (image->colorspace != cache_info->colorspace) ||
1668       (image->alpha_trait != cache_info->alpha_trait) ||
1669       (image->channels != cache_info->channels) ||
1670       (image->columns != cache_info->columns) ||
1671       (image->rows != cache_info->rows) ||
1672       (image->number_channels != cache_info->number_channels) ||
1673       (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1674       (image->metacontent_extent != cache_info->metacontent_extent) ||
1675       (cache_info->nexus_info == (NexusInfo **) NULL))
1676     return(MagickFalse);
1677   return(MagickTrue);
1678 }
1679 
GetImagePixelCache(Image * image,const MagickBooleanType clone,ExceptionInfo * exception)1680 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1681   ExceptionInfo *exception)
1682 {
1683   CacheInfo
1684     *magick_restrict cache_info;
1685 
1686   MagickBooleanType
1687     destroy,
1688     status;
1689 
1690   static MagickSizeType
1691     cache_timelimit = MagickResourceInfinity,
1692     cpu_throttle = MagickResourceInfinity,
1693     cycles = 0;
1694 
1695   status=MagickTrue;
1696   if (cpu_throttle == MagickResourceInfinity)
1697     cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1698   if ((cpu_throttle != 0) && ((cycles++ % 32) == 0))
1699     MagickDelay(cpu_throttle);
1700   if (cache_epoch == 0)
1701     {
1702       /*
1703         Set the expire time in seconds.
1704       */
1705       cache_timelimit=GetMagickResourceLimit(TimeResource);
1706       cache_epoch=GetMagickTime();
1707     }
1708   if ((cache_timelimit != MagickResourceInfinity) &&
1709       ((MagickSizeType) (GetMagickTime()-cache_epoch) >= cache_timelimit))
1710     {
1711 #if defined(ECANCELED)
1712       errno=ECANCELED;
1713 #endif
1714       cache_info=(CacheInfo *) image->cache;
1715       if (cache_info->file != -1)
1716         (void) ClosePixelCacheOnDisk(cache_info);
1717       ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1718     }
1719   LockSemaphoreInfo(image->semaphore);
1720   assert(image->cache != (Cache) NULL);
1721   cache_info=(CacheInfo *) image->cache;
1722 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1723   CopyOpenCLBuffer(cache_info);
1724 #endif
1725   destroy=MagickFalse;
1726   if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1727     {
1728       LockSemaphoreInfo(cache_info->semaphore);
1729       if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1730         {
1731           CacheInfo
1732             *clone_info;
1733 
1734           Image
1735             clone_image;
1736 
1737           /*
1738             Clone pixel cache.
1739           */
1740           clone_image=(*image);
1741           clone_image.semaphore=AcquireSemaphoreInfo();
1742           clone_image.reference_count=1;
1743           clone_image.cache=ClonePixelCache(cache_info);
1744           clone_info=(CacheInfo *) clone_image.cache;
1745           status=OpenPixelCache(&clone_image,IOMode,exception);
1746           if (status == MagickFalse)
1747             clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
1748           else
1749             {
1750               if (clone != MagickFalse)
1751                 status=ClonePixelCacheRepository(clone_info,cache_info,
1752                   exception);
1753               if (status == MagickFalse)
1754                 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
1755               else
1756                 {
1757                   destroy=MagickTrue;
1758                   image->cache=clone_info;
1759                 }
1760             }
1761           RelinquishSemaphoreInfo(&clone_image.semaphore);
1762         }
1763       UnlockSemaphoreInfo(cache_info->semaphore);
1764     }
1765   if (destroy != MagickFalse)
1766     cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1767   if (status != MagickFalse)
1768     {
1769       /*
1770         Ensure the image matches the pixel cache morphology.
1771       */
1772       if (image->type != UndefinedType)
1773         image->type=UndefinedType;
1774       if (ValidatePixelCacheMorphology(image) == MagickFalse)
1775         {
1776           status=OpenPixelCache(image,IOMode,exception);
1777           cache_info=(CacheInfo *) image->cache;
1778           if (cache_info->file != -1)
1779             (void) ClosePixelCacheOnDisk(cache_info);
1780         }
1781     }
1782   UnlockSemaphoreInfo(image->semaphore);
1783   if (status == MagickFalse)
1784     return((Cache) NULL);
1785   return(image->cache);
1786 }
1787 
1788 /*
1789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1790 %                                                                             %
1791 %                                                                             %
1792 %                                                                             %
1793 +   G e t I m a g e P i x e l C a c h e T y p e                               %
1794 %                                                                             %
1795 %                                                                             %
1796 %                                                                             %
1797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1798 %
1799 %  GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1800 %  DiskCache, MemoryCache, MapCache, or PingCache.
1801 %
1802 %  The format of the GetImagePixelCacheType() method is:
1803 %
1804 %      CacheType GetImagePixelCacheType(const Image *image)
1805 %
1806 %  A description of each parameter follows:
1807 %
1808 %    o image: the image.
1809 %
1810 */
GetImagePixelCacheType(const Image * image)1811 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1812 {
1813   CacheInfo
1814     *magick_restrict cache_info;
1815 
1816   assert(image != (Image *) NULL);
1817   assert(image->signature == MagickCoreSignature);
1818   assert(image->cache != (Cache) NULL);
1819   cache_info=(CacheInfo *) image->cache;
1820   assert(cache_info->signature == MagickCoreSignature);
1821   return(cache_info->type);
1822 }
1823 
1824 /*
1825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1826 %                                                                             %
1827 %                                                                             %
1828 %                                                                             %
1829 %   G e t O n e A u t h e n t i c P i x e l                                   %
1830 %                                                                             %
1831 %                                                                             %
1832 %                                                                             %
1833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1834 %
1835 %  GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1836 %  location.  The image background color is returned if an error occurs.
1837 %
1838 %  The format of the GetOneAuthenticPixel() method is:
1839 %
1840 %      MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1841 %        const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1842 %
1843 %  A description of each parameter follows:
1844 %
1845 %    o image: the image.
1846 %
1847 %    o x,y:  These values define the location of the pixel to return.
1848 %
1849 %    o pixel: return a pixel at the specified (x,y) location.
1850 %
1851 %    o exception: return any errors or warnings in this structure.
1852 %
1853 */
1854 
CopyPixel(const Image * image,const Quantum * source,Quantum * destination)1855 static inline MagickBooleanType CopyPixel(const Image *image,
1856   const Quantum *source,Quantum *destination)
1857 {
1858   ssize_t
1859     i;
1860 
1861   if (source == (const Quantum *) NULL)
1862     {
1863       destination[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1864       destination[GreenPixelChannel]=ClampToQuantum(
1865         image->background_color.green);
1866       destination[BluePixelChannel]=ClampToQuantum(
1867         image->background_color.blue);
1868       destination[BlackPixelChannel]=ClampToQuantum(
1869         image->background_color.black);
1870       destination[AlphaPixelChannel]=ClampToQuantum(
1871         image->background_color.alpha);
1872       return(MagickFalse);
1873     }
1874   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1875   {
1876     PixelChannel channel = GetPixelChannelChannel(image,i);
1877     destination[channel]=source[i];
1878   }
1879   return(MagickTrue);
1880 }
1881 
GetOneAuthenticPixel(Image * image,const ssize_t x,const ssize_t y,Quantum * pixel,ExceptionInfo * exception)1882 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1883   const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1884 {
1885   CacheInfo
1886     *magick_restrict cache_info;
1887 
1888   Quantum
1889     *magick_restrict q;
1890 
1891   assert(image != (Image *) NULL);
1892   assert(image->signature == MagickCoreSignature);
1893   assert(image->cache != (Cache) NULL);
1894   cache_info=(CacheInfo *) image->cache;
1895   assert(cache_info->signature == MagickCoreSignature);
1896   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1897   if (cache_info->methods.get_one_authentic_pixel_from_handler != (GetOneAuthenticPixelFromHandler) NULL)
1898     return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,pixel,exception));
1899   q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1900   return(CopyPixel(image,q,pixel));
1901 }
1902 
1903 /*
1904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1905 %                                                                             %
1906 %                                                                             %
1907 %                                                                             %
1908 +   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                 %
1909 %                                                                             %
1910 %                                                                             %
1911 %                                                                             %
1912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1913 %
1914 %  GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1915 %  location.  The image background color is returned if an error occurs.
1916 %
1917 %  The format of the GetOneAuthenticPixelFromCache() method is:
1918 %
1919 %      MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1920 %        const ssize_t x,const ssize_t y,Quantum *pixel,
1921 %        ExceptionInfo *exception)
1922 %
1923 %  A description of each parameter follows:
1924 %
1925 %    o image: the image.
1926 %
1927 %    o x,y:  These values define the location of the pixel to return.
1928 %
1929 %    o pixel: return a pixel at the specified (x,y) location.
1930 %
1931 %    o exception: return any errors or warnings in this structure.
1932 %
1933 */
GetOneAuthenticPixelFromCache(Image * image,const ssize_t x,const ssize_t y,Quantum * pixel,ExceptionInfo * exception)1934 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1935   const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1936 {
1937   CacheInfo
1938     *magick_restrict cache_info;
1939 
1940   const int
1941     id = GetOpenMPThreadId();
1942 
1943   Quantum
1944     *magick_restrict q;
1945 
1946   assert(image != (const Image *) NULL);
1947   assert(image->signature == MagickCoreSignature);
1948   assert(image->cache != (Cache) NULL);
1949   cache_info=(CacheInfo *) image->cache;
1950   assert(cache_info->signature == MagickCoreSignature);
1951   assert(id < (int) cache_info->number_threads);
1952   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1953   q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1954     exception);
1955   return(CopyPixel(image,q,pixel));
1956 }
1957 
1958 /*
1959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1960 %                                                                             %
1961 %                                                                             %
1962 %                                                                             %
1963 %   G e t O n e V i r t u a l P i x e l                                       %
1964 %                                                                             %
1965 %                                                                             %
1966 %                                                                             %
1967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1968 %
1969 %  GetOneVirtualPixel() returns a single virtual pixel at the specified
1970 %  (x,y) location.  The image background color is returned if an error occurs.
1971 %  If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1972 %
1973 %  The format of the GetOneVirtualPixel() method is:
1974 %
1975 %      MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1976 %        const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1977 %
1978 %  A description of each parameter follows:
1979 %
1980 %    o image: the image.
1981 %
1982 %    o x,y:  These values define the location of the pixel to return.
1983 %
1984 %    o pixel: return a pixel at the specified (x,y) location.
1985 %
1986 %    o exception: return any errors or warnings in this structure.
1987 %
1988 */
GetOneVirtualPixel(const Image * image,const ssize_t x,const ssize_t y,Quantum * pixel,ExceptionInfo * exception)1989 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1990   const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1991 {
1992   CacheInfo
1993     *magick_restrict cache_info;
1994 
1995   const int
1996     id = GetOpenMPThreadId();
1997 
1998   const Quantum
1999     *p;
2000 
2001   assert(image != (const Image *) NULL);
2002   assert(image->signature == MagickCoreSignature);
2003   assert(image->cache != (Cache) NULL);
2004   cache_info=(CacheInfo *) image->cache;
2005   assert(cache_info->signature == MagickCoreSignature);
2006   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2007   if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2008        (GetOneVirtualPixelFromHandler) NULL)
2009     return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2010       GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2011   assert(id < (int) cache_info->number_threads);
2012   p=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2013     1UL,1UL,cache_info->nexus_info[id],exception);
2014   return(CopyPixel(image,p,pixel));
2015 }
2016 
2017 /*
2018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2019 %                                                                             %
2020 %                                                                             %
2021 %                                                                             %
2022 +   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                     %
2023 %                                                                             %
2024 %                                                                             %
2025 %                                                                             %
2026 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2027 %
2028 %  GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2029 %  specified (x,y) location.  The image background color is returned if an
2030 %  error occurs.
2031 %
2032 %  The format of the GetOneVirtualPixelFromCache() method is:
2033 %
2034 %      MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2035 %        const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2036 %        Quantum *pixel,ExceptionInfo *exception)
2037 %
2038 %  A description of each parameter follows:
2039 %
2040 %    o image: the image.
2041 %
2042 %    o virtual_pixel_method: the virtual pixel method.
2043 %
2044 %    o x,y:  These values define the location of the pixel to return.
2045 %
2046 %    o pixel: return a pixel at the specified (x,y) location.
2047 %
2048 %    o exception: return any errors or warnings in this structure.
2049 %
2050 */
GetOneVirtualPixelFromCache(const Image * image,const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,Quantum * pixel,ExceptionInfo * exception)2051 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2052   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2053   Quantum *pixel,ExceptionInfo *exception)
2054 {
2055   CacheInfo
2056     *magick_restrict cache_info;
2057 
2058   const int
2059     id = GetOpenMPThreadId();
2060 
2061   const Quantum
2062     *p;
2063 
2064   assert(image != (const Image *) NULL);
2065   assert(image->signature == MagickCoreSignature);
2066   assert(image->cache != (Cache) NULL);
2067   cache_info=(CacheInfo *) image->cache;
2068   assert(cache_info->signature == MagickCoreSignature);
2069   assert(id < (int) cache_info->number_threads);
2070   (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2071   p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2072     cache_info->nexus_info[id],exception);
2073   return(CopyPixel(image,p,pixel));
2074 }
2075 
2076 /*
2077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2078 %                                                                             %
2079 %                                                                             %
2080 %                                                                             %
2081 %   G e t O n e V i r t u a l P i x e l I n f o                               %
2082 %                                                                             %
2083 %                                                                             %
2084 %                                                                             %
2085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2086 %
2087 %  GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2088 %  location.  The image background color is returned if an error occurs.  If
2089 %  you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2090 %
2091 %  The format of the GetOneVirtualPixelInfo() method is:
2092 %
2093 %      MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2094 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2095 %        const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2096 %
2097 %  A description of each parameter follows:
2098 %
2099 %    o image: the image.
2100 %
2101 %    o virtual_pixel_method: the virtual pixel method.
2102 %
2103 %    o x,y:  these values define the location of the pixel to return.
2104 %
2105 %    o pixel: return a pixel at the specified (x,y) location.
2106 %
2107 %    o exception: return any errors or warnings in this structure.
2108 %
2109 */
GetOneVirtualPixelInfo(const Image * image,const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,PixelInfo * pixel,ExceptionInfo * exception)2110 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2111   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2112   PixelInfo *pixel,ExceptionInfo *exception)
2113 {
2114   CacheInfo
2115     *magick_restrict cache_info;
2116 
2117   const int
2118     id = GetOpenMPThreadId();
2119 
2120   const Quantum
2121     *magick_restrict p;
2122 
2123   assert(image != (const Image *) NULL);
2124   assert(image->signature == MagickCoreSignature);
2125   assert(image->cache != (Cache) NULL);
2126   cache_info=(CacheInfo *) image->cache;
2127   assert(cache_info->signature == MagickCoreSignature);
2128   assert(id < (int) cache_info->number_threads);
2129   GetPixelInfo(image,pixel);
2130   p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2131     cache_info->nexus_info[id],exception);
2132   if (p == (const Quantum *) NULL)
2133     return(MagickFalse);
2134   GetPixelInfoPixel(image,p,pixel);
2135   return(MagickTrue);
2136 }
2137 
2138 /*
2139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2140 %                                                                             %
2141 %                                                                             %
2142 %                                                                             %
2143 +   G e t P i x e l C a c h e C o l o r s p a c e                             %
2144 %                                                                             %
2145 %                                                                             %
2146 %                                                                             %
2147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2148 %
2149 %  GetPixelCacheColorspace() returns the colorspace of the pixel cache.
2150 %
2151 %  The format of the GetPixelCacheColorspace() method is:
2152 %
2153 %      Colorspace GetPixelCacheColorspace(const Cache cache)
2154 %
2155 %  A description of each parameter follows:
2156 %
2157 %    o cache: the pixel cache.
2158 %
2159 */
GetPixelCacheColorspace(const Cache cache)2160 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2161 {
2162   CacheInfo
2163     *magick_restrict cache_info;
2164 
2165   assert(cache != (Cache) NULL);
2166   cache_info=(CacheInfo *) cache;
2167   assert(cache_info->signature == MagickCoreSignature);
2168   if (cache_info->debug != MagickFalse)
2169     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2170       cache_info->filename);
2171   return(cache_info->colorspace);
2172 }
2173 
2174 /*
2175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2176 %                                                                             %
2177 %                                                                             %
2178 %                                                                             %
2179 +   G e t P i x e l C a c h e F i l e n a m e                                 %
2180 %                                                                             %
2181 %                                                                             %
2182 %                                                                             %
2183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2184 %
2185 %  GetPixelCacheFilename() returns the filename associated with the pixel
2186 %  cache.
2187 %
2188 %  The format of the GetPixelCacheFilename() method is:
2189 %
2190 %      const char *GetPixelCacheFilename(const Image *image)
2191 %
2192 %  A description of each parameter follows:
2193 %
2194 %    o image: the image.
2195 %
2196 */
GetPixelCacheFilename(const Image * image)2197 MagickExport const char *GetPixelCacheFilename(const Image *image)
2198 {
2199   CacheInfo
2200     *magick_restrict cache_info;
2201 
2202   assert(image != (const Image *) NULL);
2203   assert(image->signature == MagickCoreSignature);
2204   assert(image->cache != (Cache) NULL);
2205   cache_info=(CacheInfo *) image->cache;
2206   assert(cache_info->signature == MagickCoreSignature);
2207   return(cache_info->cache_filename);
2208 }
2209 
2210 /*
2211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2212 %                                                                             %
2213 %                                                                             %
2214 %                                                                             %
2215 +   G e t P i x e l C a c h e M e t h o d s                                   %
2216 %                                                                             %
2217 %                                                                             %
2218 %                                                                             %
2219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2220 %
2221 %  GetPixelCacheMethods() initializes the CacheMethods structure.
2222 %
2223 %  The format of the GetPixelCacheMethods() method is:
2224 %
2225 %      void GetPixelCacheMethods(CacheMethods *cache_methods)
2226 %
2227 %  A description of each parameter follows:
2228 %
2229 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
2230 %
2231 */
GetPixelCacheMethods(CacheMethods * cache_methods)2232 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2233 {
2234   assert(cache_methods != (CacheMethods *) NULL);
2235   (void) memset(cache_methods,0,sizeof(*cache_methods));
2236   cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2237   cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2238   cache_methods->get_virtual_metacontent_from_handler=
2239     GetVirtualMetacontentFromCache;
2240   cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2241   cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2242   cache_methods->get_authentic_metacontent_from_handler=
2243     GetAuthenticMetacontentFromCache;
2244   cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2245   cache_methods->get_one_authentic_pixel_from_handler=
2246     GetOneAuthenticPixelFromCache;
2247   cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2248   cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2249   cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2250 }
2251 
2252 /*
2253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2254 %                                                                             %
2255 %                                                                             %
2256 %                                                                             %
2257 +   G e t P i x e l C a c h e N e x u s E x t e n t                           %
2258 %                                                                             %
2259 %                                                                             %
2260 %                                                                             %
2261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2262 %
2263 %  GetPixelCacheNexusExtent() returns the extent of the pixels associated
2264 %  corresponding with the last call to SetPixelCacheNexusPixels() or
2265 %  GetPixelCacheNexusPixels().
2266 %
2267 %  The format of the GetPixelCacheNexusExtent() method is:
2268 %
2269 %      MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2270 %        NexusInfo *nexus_info)
2271 %
2272 %  A description of each parameter follows:
2273 %
2274 %    o nexus_info: the nexus info.
2275 %
2276 */
GetPixelCacheNexusExtent(const Cache cache,NexusInfo * magick_restrict nexus_info)2277 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2278   NexusInfo *magick_restrict nexus_info)
2279 {
2280   CacheInfo
2281     *magick_restrict cache_info;
2282 
2283   MagickSizeType
2284     extent;
2285 
2286   assert(cache != NULL);
2287   cache_info=(CacheInfo *) cache;
2288   assert(cache_info->signature == MagickCoreSignature);
2289   extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2290   if (extent == 0)
2291     return((MagickSizeType) cache_info->columns*cache_info->rows);
2292   return(extent);
2293 }
2294 
2295 /*
2296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2297 %                                                                             %
2298 %                                                                             %
2299 %                                                                             %
2300 +   G e t P i x e l C a c h e P i x e l s                                     %
2301 %                                                                             %
2302 %                                                                             %
2303 %                                                                             %
2304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2305 %
2306 %  GetPixelCachePixels() returns the pixels associated with the specified image.
2307 %
2308 %  The format of the GetPixelCachePixels() method is:
2309 %
2310 %      void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2311 %        ExceptionInfo *exception)
2312 %
2313 %  A description of each parameter follows:
2314 %
2315 %    o image: the image.
2316 %
2317 %    o length: the pixel cache length.
2318 %
2319 %    o exception: return any errors or warnings in this structure.
2320 %
2321 */
GetPixelCachePixels(Image * image,MagickSizeType * length,ExceptionInfo * magick_unused (exception))2322 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2323   ExceptionInfo *magick_unused(exception))
2324 {
2325   CacheInfo
2326     *magick_restrict cache_info;
2327 
2328   assert(image != (const Image *) NULL);
2329   assert(image->signature == MagickCoreSignature);
2330   assert(image->cache != (Cache) NULL);
2331   assert(length != (MagickSizeType *) NULL);
2332   magick_unreferenced(exception);
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;
2706   if (extent != 0)
2707     modulo.quotient=offset/((ssize_t) extent);
2708   modulo.remainder=offset % ((ssize_t) extent);
2709   if ((modulo.remainder != 0) && ((offset ^ ((ssize_t) extent)) < 0))
2710     {
2711       modulo.quotient-=1;
2712       modulo.remainder+=((ssize_t) extent);
2713     }
2714   return(modulo);
2715 }
2716 
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)2717 MagickPrivate const Quantum *GetVirtualPixelCacheNexus(const Image *image,
2718   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2719   const size_t columns,const size_t rows,NexusInfo *nexus_info,
2720   ExceptionInfo *exception)
2721 {
2722   CacheInfo
2723     *magick_restrict cache_info;
2724 
2725   MagickOffsetType
2726     offset;
2727 
2728   MagickSizeType
2729     length,
2730     number_pixels;
2731 
2732   NexusInfo
2733     *magick_restrict virtual_nexus;
2734 
2735   Quantum
2736     *magick_restrict pixels,
2737     virtual_pixel[MaxPixelChannels];
2738 
2739   const Quantum
2740     *magick_restrict p;
2741 
2742   const void
2743     *magick_restrict r;
2744 
2745   Quantum
2746     *magick_restrict q;
2747 
2748   ssize_t
2749     i,
2750     u;
2751 
2752   unsigned char
2753     *magick_restrict s;
2754 
2755   ssize_t
2756     v;
2757 
2758   void
2759     *magick_restrict virtual_metacontent;
2760 
2761   /*
2762     Acquire pixels.
2763   */
2764   assert(image != (const Image *) NULL);
2765   assert(image->signature == MagickCoreSignature);
2766   assert(image->cache != (Cache) NULL);
2767   cache_info=(CacheInfo *) image->cache;
2768   assert(cache_info->signature == MagickCoreSignature);
2769   if (cache_info->type == UndefinedCache)
2770     return((const Quantum *) NULL);
2771 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2772   CopyOpenCLBuffer(cache_info);
2773 #endif
2774   pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,x,y,columns,rows,
2775     ((image->channels & WriteMaskChannel) != 0) ||
2776     ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
2777     nexus_info,exception);
2778   if (pixels == (Quantum *) NULL)
2779     return((const Quantum *) NULL);
2780   q=pixels;
2781   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2782     nexus_info->region.x;
2783   length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2784     nexus_info->region.width-1L;
2785   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2786   if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2787     if ((x >= 0) && ((ssize_t) (x+columns-1) < (ssize_t) cache_info->columns) &&
2788         (y >= 0) && ((ssize_t) (y+rows-1) < (ssize_t) cache_info->rows))
2789       {
2790         MagickBooleanType
2791           status;
2792 
2793         /*
2794           Pixel request is inside cache extents.
2795         */
2796         if (nexus_info->authentic_pixel_cache != MagickFalse)
2797           return(q);
2798         status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2799         if (status == MagickFalse)
2800           return((const Quantum *) NULL);
2801         if (cache_info->metacontent_extent != 0)
2802           {
2803             status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2804             if (status == MagickFalse)
2805               return((const Quantum *) NULL);
2806           }
2807         return(q);
2808       }
2809   /*
2810     Pixel request is outside cache extents.
2811   */
2812   virtual_nexus=nexus_info->virtual_nexus;
2813   s=(unsigned char *) nexus_info->metacontent;
2814   (void) memset(virtual_pixel,0,cache_info->number_channels*
2815     sizeof(*virtual_pixel));
2816   virtual_metacontent=(void *) NULL;
2817   switch (virtual_pixel_method)
2818   {
2819     case BackgroundVirtualPixelMethod:
2820     case BlackVirtualPixelMethod:
2821     case GrayVirtualPixelMethod:
2822     case TransparentVirtualPixelMethod:
2823     case MaskVirtualPixelMethod:
2824     case WhiteVirtualPixelMethod:
2825     case EdgeVirtualPixelMethod:
2826     case CheckerTileVirtualPixelMethod:
2827     case HorizontalTileVirtualPixelMethod:
2828     case VerticalTileVirtualPixelMethod:
2829     {
2830       if (cache_info->metacontent_extent != 0)
2831         {
2832           /*
2833             Acquire a metacontent buffer.
2834           */
2835           virtual_metacontent=(void *) AcquireQuantumMemory(1,
2836             cache_info->metacontent_extent);
2837           if (virtual_metacontent == (void *) NULL)
2838             {
2839               (void) ThrowMagickException(exception,GetMagickModule(),
2840                 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2841               return((const Quantum *) NULL);
2842             }
2843           (void) memset(virtual_metacontent,0,cache_info->metacontent_extent);
2844         }
2845       switch (virtual_pixel_method)
2846       {
2847         case BlackVirtualPixelMethod:
2848         {
2849           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2850             SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2851           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2852           break;
2853         }
2854         case GrayVirtualPixelMethod:
2855         {
2856           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2857             SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2858               virtual_pixel);
2859           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2860           break;
2861         }
2862         case TransparentVirtualPixelMethod:
2863         {
2864           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2865             SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2866           SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2867           break;
2868         }
2869         case MaskVirtualPixelMethod:
2870         case WhiteVirtualPixelMethod:
2871         {
2872           for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2873             SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2874           SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2875           break;
2876         }
2877         default:
2878         {
2879           SetPixelRed(image,ClampToQuantum(image->background_color.red),
2880             virtual_pixel);
2881           SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2882             virtual_pixel);
2883           SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2884             virtual_pixel);
2885           SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2886             virtual_pixel);
2887           SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2888             virtual_pixel);
2889           break;
2890         }
2891       }
2892       break;
2893     }
2894     default:
2895       break;
2896   }
2897   for (v=0; v < (ssize_t) rows; v++)
2898   {
2899     ssize_t
2900       y_offset;
2901 
2902     y_offset=y+v;
2903     if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2904         (virtual_pixel_method == UndefinedVirtualPixelMethod))
2905       y_offset=EdgeY(y_offset,cache_info->rows);
2906     for (u=0; u < (ssize_t) columns; u+=length)
2907     {
2908       ssize_t
2909         x_offset;
2910 
2911       x_offset=x+u;
2912       length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2913       if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2914           ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2915           (length == 0))
2916         {
2917           MagickModulo
2918             x_modulo,
2919             y_modulo;
2920 
2921           /*
2922             Transfer a single pixel.
2923           */
2924           length=(MagickSizeType) 1;
2925           switch (virtual_pixel_method)
2926           {
2927             case EdgeVirtualPixelMethod:
2928             default:
2929             {
2930               p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2931                 EdgeX(x_offset,cache_info->columns),
2932                 EdgeY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
2933                 exception);
2934               r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2935               break;
2936             }
2937             case RandomVirtualPixelMethod:
2938             {
2939               if (cache_info->random_info == (RandomInfo *) NULL)
2940                 cache_info->random_info=AcquireRandomInfo();
2941               p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2942                 RandomX(cache_info->random_info,cache_info->columns),
2943                 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2944                 virtual_nexus,exception);
2945               r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2946               break;
2947             }
2948             case DitherVirtualPixelMethod:
2949             {
2950               p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2951                 DitherX(x_offset,cache_info->columns),
2952                 DitherY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
2953                 exception);
2954               r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2955               break;
2956             }
2957             case TileVirtualPixelMethod:
2958             {
2959               x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2960               y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2961               p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2962                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
2963                 exception);
2964               r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2965               break;
2966             }
2967             case MirrorVirtualPixelMethod:
2968             {
2969               x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2970               if ((x_modulo.quotient & 0x01) == 1L)
2971                 x_modulo.remainder=(ssize_t) cache_info->columns-
2972                   x_modulo.remainder-1L;
2973               y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2974               if ((y_modulo.quotient & 0x01) == 1L)
2975                 y_modulo.remainder=(ssize_t) cache_info->rows-
2976                   y_modulo.remainder-1L;
2977               p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2978                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
2979                 exception);
2980               r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2981               break;
2982             }
2983             case HorizontalTileEdgeVirtualPixelMethod:
2984             {
2985               x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2986               p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2987                 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2988                 virtual_nexus,exception);
2989               r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2990               break;
2991             }
2992             case VerticalTileEdgeVirtualPixelMethod:
2993             {
2994               y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2995               p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2996                 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2997                 virtual_nexus,exception);
2998               r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2999               break;
3000             }
3001             case BackgroundVirtualPixelMethod:
3002             case BlackVirtualPixelMethod:
3003             case GrayVirtualPixelMethod:
3004             case TransparentVirtualPixelMethod:
3005             case MaskVirtualPixelMethod:
3006             case WhiteVirtualPixelMethod:
3007             {
3008               p=virtual_pixel;
3009               r=virtual_metacontent;
3010               break;
3011             }
3012             case CheckerTileVirtualPixelMethod:
3013             {
3014               x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3015               y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3016               if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3017                 {
3018                   p=virtual_pixel;
3019                   r=virtual_metacontent;
3020                   break;
3021                 }
3022               p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3023                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3024                 exception);
3025               r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3026               break;
3027             }
3028             case HorizontalTileVirtualPixelMethod:
3029             {
3030               if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
3031                 {
3032                   p=virtual_pixel;
3033                   r=virtual_metacontent;
3034                   break;
3035                 }
3036               x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3037               y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3038               p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3039                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3040                 exception);
3041               r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3042               break;
3043             }
3044             case VerticalTileVirtualPixelMethod:
3045             {
3046               if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
3047                 {
3048                   p=virtual_pixel;
3049                   r=virtual_metacontent;
3050                   break;
3051                 }
3052               x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3053               y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3054               p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3055                 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3056                 exception);
3057               r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3058               break;
3059             }
3060           }
3061           if (p == (const Quantum *) NULL)
3062             break;
3063           (void) memcpy(q,p,(size_t) (cache_info->number_channels*length*
3064             sizeof(*p)));
3065           q+=cache_info->number_channels;
3066           if ((s != (void *) NULL) && (r != (const void *) NULL))
3067             {
3068               (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3069               s+=cache_info->metacontent_extent;
3070             }
3071           continue;
3072         }
3073       /*
3074         Transfer a run of pixels.
3075       */
3076       p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x_offset,y_offset,
3077         (size_t) length,1UL,virtual_nexus,exception);
3078       if (p == (const Quantum *) NULL)
3079         break;
3080       r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3081       (void) memcpy(q,p,(size_t) (cache_info->number_channels*length*
3082         sizeof(*p)));
3083       q+=cache_info->number_channels*length;
3084       if ((r != (void *) NULL) && (s != (const void *) NULL))
3085         {
3086           (void) memcpy(s,r,(size_t) length);
3087           s+=length*cache_info->metacontent_extent;
3088         }
3089     }
3090     if (u < (ssize_t) columns)
3091       break;
3092   }
3093   /*
3094     Free resources.
3095   */
3096   if (virtual_metacontent != (void *) NULL)
3097     virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3098   if (v < (ssize_t) rows)
3099     return((const Quantum *) NULL);
3100   return(pixels);
3101 }
3102 
3103 /*
3104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3105 %                                                                             %
3106 %                                                                             %
3107 %                                                                             %
3108 +   G e t V i r t u a l P i x e l C a c h e                                   %
3109 %                                                                             %
3110 %                                                                             %
3111 %                                                                             %
3112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3113 %
3114 %  GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3115 %  cache as defined by the geometry parameters.   A pointer to the pixels
3116 %  is returned if the pixels are transferred, otherwise a NULL is returned.
3117 %
3118 %  The format of the GetVirtualPixelCache() method is:
3119 %
3120 %      const Quantum *GetVirtualPixelCache(const Image *image,
3121 %        const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3122 %        const ssize_t y,const size_t columns,const size_t rows,
3123 %        ExceptionInfo *exception)
3124 %
3125 %  A description of each parameter follows:
3126 %
3127 %    o image: the image.
3128 %
3129 %    o virtual_pixel_method: the virtual pixel method.
3130 %
3131 %    o x,y,columns,rows:  These values define the perimeter of a region of
3132 %      pixels.
3133 %
3134 %    o exception: return any errors or warnings in this structure.
3135 %
3136 */
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)3137 static const Quantum *GetVirtualPixelCache(const Image *image,
3138   const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3139   const size_t columns,const size_t rows,ExceptionInfo *exception)
3140 {
3141   CacheInfo
3142     *magick_restrict cache_info;
3143 
3144   const int
3145     id = GetOpenMPThreadId();
3146 
3147   const Quantum
3148     *magick_restrict p;
3149 
3150   assert(image != (const Image *) NULL);
3151   assert(image->signature == MagickCoreSignature);
3152   assert(image->cache != (Cache) NULL);
3153   cache_info=(CacheInfo *) image->cache;
3154   assert(cache_info->signature == MagickCoreSignature);
3155   assert(id < (int) cache_info->number_threads);
3156   p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,columns,rows,
3157     cache_info->nexus_info[id],exception);
3158   return(p);
3159 }
3160 
3161 /*
3162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3163 %                                                                             %
3164 %                                                                             %
3165 %                                                                             %
3166 %   G e t V i r t u a l P i x e l Q u e u e                                   %
3167 %                                                                             %
3168 %                                                                             %
3169 %                                                                             %
3170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3171 %
3172 %  GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3173 %  with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3174 %
3175 %  The format of the GetVirtualPixelQueue() method is:
3176 %
3177 %      const Quantum *GetVirtualPixelQueue(const Image image)
3178 %
3179 %  A description of each parameter follows:
3180 %
3181 %    o image: the image.
3182 %
3183 */
GetVirtualPixelQueue(const Image * image)3184 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3185 {
3186   CacheInfo
3187     *magick_restrict cache_info;
3188 
3189   const int
3190     id = GetOpenMPThreadId();
3191 
3192   assert(image != (const Image *) NULL);
3193   assert(image->signature == MagickCoreSignature);
3194   assert(image->cache != (Cache) NULL);
3195   cache_info=(CacheInfo *) image->cache;
3196   assert(cache_info->signature == MagickCoreSignature);
3197   if (cache_info->methods.get_virtual_pixels_handler !=
3198        (GetVirtualPixelsHandler) NULL)
3199     return(cache_info->methods.get_virtual_pixels_handler(image));
3200   assert(id < (int) cache_info->number_threads);
3201   return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3202 }
3203 
3204 /*
3205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3206 %                                                                             %
3207 %                                                                             %
3208 %                                                                             %
3209 %   G e t V i r t u a l P i x e l s                                           %
3210 %                                                                             %
3211 %                                                                             %
3212 %                                                                             %
3213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3214 %
3215 %  GetVirtualPixels() returns an immutable pixel region. If the
3216 %  region is successfully accessed, a pointer to it is returned, otherwise
3217 %  NULL is returned.  The returned pointer may point to a temporary working
3218 %  copy of the pixels or it may point to the original pixels in memory.
3219 %  Performance is maximized if the selected region is part of one row, or one
3220 %  or more full rows, since there is opportunity to access the pixels in-place
3221 %  (without a copy) if the image is in memory, or in a memory-mapped file.  The
3222 %  returned pointer must *never* be deallocated by the user.
3223 %
3224 %  Pixels accessed via the returned pointer represent a simple array of type
3225 %  Quantum.  If the image type is CMYK or the storage class is PseudoClass,
3226 %  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3227 %  access the meta-content (of type void) corresponding to the
3228 %  region.
3229 %
3230 %  If you plan to modify the pixels, use GetAuthenticPixels() instead.
3231 %
3232 %  Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3233 %  safe.  In a threaded environment, use GetCacheViewVirtualPixels() or
3234 %  GetCacheViewAuthenticPixels() instead.
3235 %
3236 %  The format of the GetVirtualPixels() method is:
3237 %
3238 %      const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3239 %        const ssize_t y,const size_t columns,const size_t rows,
3240 %        ExceptionInfo *exception)
3241 %
3242 %  A description of each parameter follows:
3243 %
3244 %    o image: the image.
3245 %
3246 %    o x,y,columns,rows:  These values define the perimeter of a region of
3247 %      pixels.
3248 %
3249 %    o exception: return any errors or warnings in this structure.
3250 %
3251 */
GetVirtualPixels(const Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,ExceptionInfo * exception)3252 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3253   const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3254   ExceptionInfo *exception)
3255 {
3256   CacheInfo
3257     *magick_restrict cache_info;
3258 
3259   const int
3260     id = GetOpenMPThreadId();
3261 
3262   const Quantum
3263     *magick_restrict p;
3264 
3265   assert(image != (const Image *) NULL);
3266   assert(image->signature == MagickCoreSignature);
3267   assert(image->cache != (Cache) NULL);
3268   cache_info=(CacheInfo *) image->cache;
3269   assert(cache_info->signature == MagickCoreSignature);
3270   if (cache_info->methods.get_virtual_pixel_handler !=
3271        (GetVirtualPixelHandler) NULL)
3272     return(cache_info->methods.get_virtual_pixel_handler(image,
3273       GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3274   assert(id < (int) cache_info->number_threads);
3275   p=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3276     columns,rows,cache_info->nexus_info[id],exception);
3277   return(p);
3278 }
3279 
3280 /*
3281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3282 %                                                                             %
3283 %                                                                             %
3284 %                                                                             %
3285 +   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                         %
3286 %                                                                             %
3287 %                                                                             %
3288 %                                                                             %
3289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3290 %
3291 %  GetVirtualPixelsCache() returns the pixels associated corresponding with the
3292 %  last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3293 %
3294 %  The format of the GetVirtualPixelsCache() method is:
3295 %
3296 %      Quantum *GetVirtualPixelsCache(const Image *image)
3297 %
3298 %  A description of each parameter follows:
3299 %
3300 %    o image: the image.
3301 %
3302 */
GetVirtualPixelsCache(const Image * image)3303 static const Quantum *GetVirtualPixelsCache(const Image *image)
3304 {
3305   CacheInfo
3306     *magick_restrict cache_info;
3307 
3308   const int
3309     id = GetOpenMPThreadId();
3310 
3311   assert(image != (const Image *) NULL);
3312   assert(image->signature == MagickCoreSignature);
3313   assert(image->cache != (Cache) NULL);
3314   cache_info=(CacheInfo *) image->cache;
3315   assert(cache_info->signature == MagickCoreSignature);
3316   assert(id < (int) cache_info->number_threads);
3317   return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3318 }
3319 
3320 /*
3321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3322 %                                                                             %
3323 %                                                                             %
3324 %                                                                             %
3325 +   G e t V i r t u a l P i x e l s N e x u s                                 %
3326 %                                                                             %
3327 %                                                                             %
3328 %                                                                             %
3329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3330 %
3331 %  GetVirtualPixelsNexus() returns the pixels associated with the specified
3332 %  cache nexus.
3333 %
3334 %  The format of the GetVirtualPixelsNexus() method is:
3335 %
3336 %      const Quantum *GetVirtualPixelsNexus(const Cache cache,
3337 %        NexusInfo *nexus_info)
3338 %
3339 %  A description of each parameter follows:
3340 %
3341 %    o cache: the pixel cache.
3342 %
3343 %    o nexus_info: the cache nexus to return the colormap pixels.
3344 %
3345 */
GetVirtualPixelsNexus(const Cache cache,NexusInfo * magick_restrict nexus_info)3346 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3347   NexusInfo *magick_restrict nexus_info)
3348 {
3349   CacheInfo
3350     *magick_restrict cache_info;
3351 
3352   assert(cache != (Cache) NULL);
3353   cache_info=(CacheInfo *) cache;
3354   assert(cache_info->signature == MagickCoreSignature);
3355   if (cache_info->storage_class == UndefinedClass)
3356     return((Quantum *) NULL);
3357   return((const Quantum *) nexus_info->pixels);
3358 }
3359 
3360 /*
3361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3362 %                                                                             %
3363 %                                                                             %
3364 %                                                                             %
3365 +   M a s k P i x e l C a c h e N e x u s                                     %
3366 %                                                                             %
3367 %                                                                             %
3368 %                                                                             %
3369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3370 %
3371 %  MaskPixelCacheNexus() masks the cache nexus as defined by the composite mask.
3372 %  The method returns MagickTrue if the pixel region is masked, otherwise
3373 %  MagickFalse.
3374 %
3375 %  The format of the MaskPixelCacheNexus() method is:
3376 %
3377 %      MagickBooleanType MaskPixelCacheNexus(Image *image,
3378 %        NexusInfo *nexus_info,ExceptionInfo *exception)
3379 %
3380 %  A description of each parameter follows:
3381 %
3382 %    o image: the image.
3383 %
3384 %    o nexus_info: the cache nexus to clip.
3385 %
3386 %    o exception: return any errors or warnings in this structure.
3387 %
3388 */
3389 
ApplyPixelCompositeMask(const Quantum p,const MagickRealType alpha,const Quantum q,const MagickRealType beta)3390 static inline Quantum ApplyPixelCompositeMask(const Quantum p,
3391   const MagickRealType alpha,const Quantum q,const MagickRealType beta)
3392 {
3393   double
3394     gamma;
3395 
3396   if (fabs((double) (alpha-TransparentAlpha)) < MagickEpsilon)
3397     return(q);
3398   gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3399   gamma=PerceptibleReciprocal(gamma);
3400   return(ClampToQuantum(gamma*MagickOver_((double) p,alpha,(double) q,beta)));
3401 }
3402 
MaskPixelCacheNexus(Image * image,NexusInfo * nexus_info,ExceptionInfo * exception)3403 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3404   ExceptionInfo *exception)
3405 {
3406   CacheInfo
3407     *magick_restrict cache_info;
3408 
3409   Quantum
3410     *magick_restrict p,
3411     *magick_restrict q;
3412 
3413   ssize_t
3414     y;
3415 
3416   /*
3417     Apply composite mask.
3418   */
3419   if (image->debug != MagickFalse)
3420     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3421   if ((image->channels & CompositeMaskChannel) == 0)
3422     return(MagickTrue);
3423   if ((nexus_info->region.width == 0) || (nexus_info->region.height == 0))
3424     return(MagickTrue);
3425   cache_info=(CacheInfo *) image->cache;
3426   if (cache_info == (Cache) NULL)
3427     return(MagickFalse);
3428   p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3429     nexus_info->region.width,nexus_info->region.height,
3430     nexus_info->virtual_nexus,exception);
3431   q=nexus_info->pixels;
3432   if ((p == (Quantum *) NULL) || (q == (Quantum *) NULL))
3433     return(MagickFalse);
3434   for (y=0; y < (ssize_t) nexus_info->region.height; y++)
3435   {
3436     ssize_t
3437       x;
3438 
3439     for (x=0; x < (ssize_t) nexus_info->region.width; x++)
3440     {
3441       double
3442         alpha;
3443 
3444       ssize_t
3445         i;
3446 
3447       alpha=(double) GetPixelCompositeMask(image,p);
3448       for (i=0; i < (ssize_t) image->number_channels; i++)
3449       {
3450         PixelChannel channel = GetPixelChannelChannel(image,i);
3451         PixelTrait traits = GetPixelChannelTraits(image,channel);
3452         if ((traits & UpdatePixelTrait) == 0)
3453           continue;
3454         q[i]=ApplyPixelCompositeMask(q[i],alpha,p[i],GetPixelAlpha(image,p));
3455       }
3456       p+=GetPixelChannels(image);
3457       q+=GetPixelChannels(image);
3458     }
3459   }
3460   return(MagickTrue);
3461 }
3462 
3463 /*
3464 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3465 %                                                                             %
3466 %                                                                             %
3467 %                                                                             %
3468 +   O p e n P i x e l C a c h e                                               %
3469 %                                                                             %
3470 %                                                                             %
3471 %                                                                             %
3472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3473 %
3474 %  OpenPixelCache() allocates the pixel cache.  This includes defining the cache
3475 %  dimensions, allocating space for the image pixels and optionally the
3476 %  metacontent, and memory mapping the cache if it is disk based.  The cache
3477 %  nexus array is initialized as well.
3478 %
3479 %  The format of the OpenPixelCache() method is:
3480 %
3481 %      MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3482 %        ExceptionInfo *exception)
3483 %
3484 %  A description of each parameter follows:
3485 %
3486 %    o image: the image.
3487 %
3488 %    o mode: ReadMode, WriteMode, or IOMode.
3489 %
3490 %    o exception: return any errors or warnings in this structure.
3491 %
3492 */
3493 
OpenPixelCacheOnDisk(CacheInfo * cache_info,const MapMode mode)3494 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3495   const MapMode mode)
3496 {
3497   int
3498     file;
3499 
3500   /*
3501     Open pixel cache on disk.
3502   */
3503   if ((cache_info->file != -1) && (cache_info->disk_mode == mode))
3504     return(MagickTrue);  /* cache already open and in the proper mode */
3505   if (*cache_info->cache_filename == '\0')
3506     file=AcquireUniqueFileResource(cache_info->cache_filename);
3507   else
3508     switch (mode)
3509     {
3510       case ReadMode:
3511       {
3512         file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3513         break;
3514       }
3515       case WriteMode:
3516       {
3517         file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3518           O_BINARY | O_EXCL,S_MODE);
3519         if (file == -1)
3520           file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3521         break;
3522       }
3523       case IOMode:
3524       default:
3525       {
3526         file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3527           O_EXCL,S_MODE);
3528         if (file == -1)
3529           file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3530         break;
3531       }
3532     }
3533   if (file == -1)
3534     return(MagickFalse);
3535   (void) AcquireMagickResource(FileResource,1);
3536   if (cache_info->file != -1)
3537     (void) ClosePixelCacheOnDisk(cache_info);
3538   cache_info->file=file;
3539   cache_info->disk_mode=mode;
3540   return(MagickTrue);
3541 }
3542 
WritePixelCacheRegion(const CacheInfo * magick_restrict cache_info,const MagickOffsetType offset,const MagickSizeType length,const unsigned char * magick_restrict buffer)3543 static inline MagickOffsetType WritePixelCacheRegion(
3544   const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3545   const MagickSizeType length,const unsigned char *magick_restrict buffer)
3546 {
3547   MagickOffsetType
3548     i;
3549 
3550   ssize_t
3551     count;
3552 
3553 #if !defined(MAGICKCORE_HAVE_PWRITE)
3554   if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3555     return((MagickOffsetType) -1);
3556 #endif
3557   count=0;
3558   for (i=0; i < (MagickOffsetType) length; i+=count)
3559   {
3560 #if !defined(MAGICKCORE_HAVE_PWRITE)
3561     count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3562       MAGICK_SSIZE_MAX));
3563 #else
3564     count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3565       MAGICK_SSIZE_MAX),offset+i);
3566 #endif
3567     if (count <= 0)
3568       {
3569         count=0;
3570         if (errno != EINTR)
3571           break;
3572       }
3573   }
3574   return(i);
3575 }
3576 
SetPixelCacheExtent(Image * image,MagickSizeType length)3577 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3578 {
3579   CacheInfo
3580     *magick_restrict cache_info;
3581 
3582   MagickOffsetType
3583     count,
3584     extent,
3585     offset;
3586 
3587   cache_info=(CacheInfo *) image->cache;
3588   if (image->debug != MagickFalse)
3589     {
3590       char
3591         format[MagickPathExtent],
3592         message[MagickPathExtent];
3593 
3594       (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3595       (void) FormatLocaleString(message,MagickPathExtent,
3596         "extend %s (%s[%d], disk, %s)",cache_info->filename,
3597         cache_info->cache_filename,cache_info->file,format);
3598       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3599     }
3600   if (length != (MagickSizeType) ((MagickOffsetType) length))
3601     return(MagickFalse);
3602   offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3603   if (offset < 0)
3604     return(MagickFalse);
3605   if ((MagickSizeType) offset >= length)
3606     count=(MagickOffsetType) 1;
3607   else
3608     {
3609       extent=(MagickOffsetType) length-1;
3610       count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3611         "");
3612       if (count != 1)
3613         return(MagickFalse);
3614 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3615       if (cache_info->synchronize != MagickFalse)
3616         if (posix_fallocate(cache_info->file,offset+1,extent-offset) != 0)
3617           return(MagickFalse);
3618 #endif
3619     }
3620   offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3621   if (offset < 0)
3622     return(MagickFalse);
3623   return(MagickTrue);
3624 }
3625 
OpenPixelCache(Image * image,const MapMode mode,ExceptionInfo * exception)3626 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3627   ExceptionInfo *exception)
3628 {
3629   CacheInfo
3630     *magick_restrict cache_info,
3631     source_info;
3632 
3633   char
3634     format[MagickPathExtent],
3635     message[MagickPathExtent];
3636 
3637   const char
3638     *hosts,
3639     *type;
3640 
3641   MagickBooleanType
3642     status;
3643 
3644   MagickSizeType
3645     length,
3646     number_pixels;
3647 
3648   size_t
3649     columns,
3650     packet_size;
3651 
3652   assert(image != (const Image *) NULL);
3653   assert(image->signature == MagickCoreSignature);
3654   assert(image->cache != (Cache) NULL);
3655   if (image->debug != MagickFalse)
3656     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3657   if (cache_anonymous_memory < 0)
3658     {
3659       char
3660         *value;
3661 
3662       /*
3663         Does the security policy require anonymous mapping for pixel cache?
3664       */
3665       cache_anonymous_memory=0;
3666       value=GetPolicyValue("pixel-cache-memory");
3667       if (value == (char *) NULL)
3668         value=GetPolicyValue("cache:memory-map");
3669       if (LocaleCompare(value,"anonymous") == 0)
3670         {
3671 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3672           cache_anonymous_memory=1;
3673 #else
3674           (void) ThrowMagickException(exception,GetMagickModule(),
3675             MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3676             "'%s' (policy requires anonymous memory mapping)",image->filename);
3677 #endif
3678         }
3679       value=DestroyString(value);
3680     }
3681   if ((image->columns == 0) || (image->rows == 0))
3682     ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3683   cache_info=(CacheInfo *) image->cache;
3684   assert(cache_info->signature == MagickCoreSignature);
3685   if (((MagickSizeType) image->columns > cache_info->width_limit) ||
3686       ((MagickSizeType) image->rows > cache_info->height_limit))
3687     ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
3688       image->filename);
3689   if (GetMagickResourceLimit(ListLengthResource) != MagickResourceInfinity)
3690     {
3691       length=GetImageListLength(image);
3692       if (AcquireMagickResource(ListLengthResource,length) == MagickFalse)
3693         ThrowBinaryException(ResourceLimitError,"ListLengthExceedsLimit",
3694           image->filename);
3695     }
3696   source_info=(*cache_info);
3697   source_info.file=(-1);
3698   (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3699     image->filename,(double) image->scene);
3700   cache_info->storage_class=image->storage_class;
3701   cache_info->colorspace=image->colorspace;
3702   cache_info->alpha_trait=image->alpha_trait;
3703   cache_info->channels=image->channels;
3704   cache_info->rows=image->rows;
3705   cache_info->columns=image->columns;
3706   InitializePixelChannelMap(image);
3707   cache_info->number_channels=GetPixelChannels(image);
3708   (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3709     sizeof(*image->channel_map));
3710   cache_info->metacontent_extent=image->metacontent_extent;
3711   cache_info->mode=mode;
3712   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3713   packet_size=MagickMax(cache_info->number_channels,1)*sizeof(Quantum);
3714   if (image->metacontent_extent != 0)
3715     packet_size+=cache_info->metacontent_extent;
3716   length=number_pixels*packet_size;
3717   columns=(size_t) (length/cache_info->rows/packet_size);
3718   if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3719       ((ssize_t) cache_info->rows < 0))
3720     ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3721       image->filename);
3722   cache_info->length=length;
3723   if (image->ping != MagickFalse)
3724     {
3725       cache_info->type=PingCache;
3726       return(MagickTrue);
3727     }
3728   status=AcquireMagickResource(AreaResource,(MagickSizeType)
3729     cache_info->columns*cache_info->rows);
3730   if (cache_info->mode == PersistMode)
3731     status=MagickFalse;
3732   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3733     cache_info->metacontent_extent);
3734   if ((status != MagickFalse) &&
3735       (length == (MagickSizeType) ((size_t) length)) &&
3736       ((cache_info->type == UndefinedCache) ||
3737        (cache_info->type == MemoryCache)))
3738     {
3739       status=AcquireMagickResource(MemoryResource,cache_info->length);
3740       if (status != MagickFalse)
3741         {
3742           status=MagickTrue;
3743           if (cache_anonymous_memory <= 0)
3744             {
3745               cache_info->mapped=MagickFalse;
3746               cache_info->pixels=(Quantum *) MagickAssumeAligned(
3747                 AcquireAlignedMemory(1,(size_t) cache_info->length));
3748             }
3749           else
3750             {
3751               cache_info->mapped=MagickTrue;
3752               cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3753                 cache_info->length);
3754             }
3755           if (cache_info->pixels == (Quantum *) NULL)
3756             {
3757               cache_info->mapped=source_info.mapped;
3758               cache_info->pixels=source_info.pixels;
3759             }
3760           else
3761             {
3762               /*
3763                 Create memory pixel cache.
3764               */
3765               cache_info->type=MemoryCache;
3766               cache_info->metacontent=(void *) NULL;
3767               if (cache_info->metacontent_extent != 0)
3768                 cache_info->metacontent=(void *) (cache_info->pixels+
3769                   cache_info->number_channels*number_pixels);
3770               if ((source_info.storage_class != UndefinedClass) &&
3771                   (mode != ReadMode))
3772                 {
3773                   status=ClonePixelCacheRepository(cache_info,&source_info,
3774                     exception);
3775                   RelinquishPixelCachePixels(&source_info);
3776                 }
3777               if (image->debug != MagickFalse)
3778                 {
3779                   (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3780                     MagickPathExtent,format);
3781                   type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3782                     cache_info->type);
3783                   (void) FormatLocaleString(message,MagickPathExtent,
3784                     "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3785                     cache_info->filename,cache_info->mapped != MagickFalse ?
3786                     "Anonymous" : "Heap",type,(double) cache_info->columns,
3787                     (double) cache_info->rows,(double)
3788                     cache_info->number_channels,format);
3789                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3790                     message);
3791                 }
3792               cache_info->storage_class=image->storage_class;
3793               if (status == 0)
3794                 {
3795                   cache_info->type=UndefinedCache;
3796                   return(MagickFalse);
3797                 }
3798               return(MagickTrue);
3799             }
3800         }
3801     }
3802   status=AcquireMagickResource(DiskResource,cache_info->length);
3803   hosts=(const char *) GetImageRegistry(StringRegistryType,"cache:hosts",
3804     exception);
3805   if ((status == MagickFalse) && (hosts != (const char *) NULL))
3806     {
3807       DistributeCacheInfo
3808         *server_info;
3809 
3810       /*
3811         Distribute the pixel cache to a remote server.
3812       */
3813       server_info=AcquireDistributeCacheInfo(exception);
3814       if (server_info != (DistributeCacheInfo *) NULL)
3815         {
3816           status=OpenDistributePixelCache(server_info,image);
3817           if (status == MagickFalse)
3818             {
3819               ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3820                 GetDistributeCacheHostname(server_info));
3821               server_info=DestroyDistributeCacheInfo(server_info);
3822             }
3823           else
3824             {
3825               /*
3826                 Create a distributed pixel cache.
3827               */
3828               status=MagickTrue;
3829               cache_info->type=DistributedCache;
3830               cache_info->server_info=server_info;
3831               (void) FormatLocaleString(cache_info->cache_filename,
3832                 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3833                 (DistributeCacheInfo *) cache_info->server_info),
3834                 GetDistributeCachePort((DistributeCacheInfo *)
3835                 cache_info->server_info));
3836               if ((source_info.storage_class != UndefinedClass) &&
3837                   (mode != ReadMode))
3838                 {
3839                   status=ClonePixelCacheRepository(cache_info,&source_info,
3840                     exception);
3841                   RelinquishPixelCachePixels(&source_info);
3842                 }
3843               if (image->debug != MagickFalse)
3844                 {
3845                   (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3846                     MagickPathExtent,format);
3847                   type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3848                     cache_info->type);
3849                   (void) FormatLocaleString(message,MagickPathExtent,
3850                     "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3851                     cache_info->filename,cache_info->cache_filename,
3852                     GetDistributeCacheFile((DistributeCacheInfo *)
3853                     cache_info->server_info),type,(double) cache_info->columns,
3854                     (double) cache_info->rows,(double)
3855                     cache_info->number_channels,format);
3856                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3857                     message);
3858                 }
3859               if (status == 0)
3860                 {
3861                   cache_info->type=UndefinedCache;
3862                   return(MagickFalse);
3863                 }
3864               return(MagickTrue);
3865             }
3866         }
3867       cache_info->type=UndefinedCache;
3868       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3869         "CacheResourcesExhausted","`%s'",image->filename);
3870       return(MagickFalse);
3871     }
3872   /*
3873     Create pixel cache on disk.
3874   */
3875   if (status == MagickFalse)
3876     {
3877       cache_info->type=UndefinedCache;
3878       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3879         "CacheResourcesExhausted","`%s'",image->filename);
3880       return(MagickFalse);
3881     }
3882   if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode) &&
3883       (cache_info->mode != PersistMode))
3884     {
3885       (void) ClosePixelCacheOnDisk(cache_info);
3886       *cache_info->cache_filename='\0';
3887     }
3888   if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3889     {
3890       cache_info->type=UndefinedCache;
3891       ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3892         image->filename);
3893       return(MagickFalse);
3894     }
3895   status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3896     cache_info->length);
3897   if (status == MagickFalse)
3898     {
3899       cache_info->type=UndefinedCache;
3900       ThrowFileException(exception,CacheError,"UnableToExtendCache",
3901         image->filename);
3902       return(MagickFalse);
3903     }
3904   cache_info->type=DiskCache;
3905   length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3906     cache_info->metacontent_extent);
3907   if (length == (MagickSizeType) ((size_t) length))
3908     {
3909       status=AcquireMagickResource(MapResource,cache_info->length);
3910       if (status != MagickFalse)
3911         {
3912           cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3913             cache_info->offset,(size_t) cache_info->length);
3914           if (cache_info->pixels == (Quantum *) NULL)
3915             {
3916               cache_info->mapped=source_info.mapped;
3917               cache_info->pixels=source_info.pixels;
3918               RelinquishMagickResource(MapResource,cache_info->length);
3919             }
3920           else
3921             {
3922               /*
3923                 Create file-backed memory-mapped pixel cache.
3924               */
3925               (void) ClosePixelCacheOnDisk(cache_info);
3926               cache_info->type=MapCache;
3927               cache_info->mapped=MagickTrue;
3928               cache_info->metacontent=(void *) NULL;
3929               if (cache_info->metacontent_extent != 0)
3930                 cache_info->metacontent=(void *) (cache_info->pixels+
3931                   cache_info->number_channels*number_pixels);
3932               if ((source_info.storage_class != UndefinedClass) &&
3933                   (mode != ReadMode))
3934                 {
3935                   status=ClonePixelCacheRepository(cache_info,&source_info,
3936                     exception);
3937                   RelinquishPixelCachePixels(&source_info);
3938                 }
3939               if (image->debug != MagickFalse)
3940                 {
3941                   (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3942                     MagickPathExtent,format);
3943                   type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3944                     cache_info->type);
3945                   (void) FormatLocaleString(message,MagickPathExtent,
3946                     "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3947                     cache_info->filename,cache_info->cache_filename,
3948                     cache_info->file,type,(double) cache_info->columns,
3949                     (double) cache_info->rows,(double)
3950                     cache_info->number_channels,format);
3951                   (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3952                     message);
3953                 }
3954               if (status == 0)
3955                 {
3956                   cache_info->type=UndefinedCache;
3957                   return(MagickFalse);
3958                 }
3959               return(MagickTrue);
3960             }
3961         }
3962     }
3963   status=MagickTrue;
3964   if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3965     {
3966       status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3967       RelinquishPixelCachePixels(&source_info);
3968     }
3969   if (image->debug != MagickFalse)
3970     {
3971       (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3972         MagickPathExtent,format);
3973       type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3974         cache_info->type);
3975       (void) FormatLocaleString(message,MagickPathExtent,
3976         "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3977         cache_info->cache_filename,cache_info->file,type,(double)
3978         cache_info->columns,(double) cache_info->rows,(double)
3979         cache_info->number_channels,format);
3980       (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3981     }
3982   if (status == 0)
3983     {
3984       cache_info->type=UndefinedCache;
3985       return(MagickFalse);
3986     }
3987   return(MagickTrue);
3988 }
3989 
3990 /*
3991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3992 %                                                                             %
3993 %                                                                             %
3994 %                                                                             %
3995 +   P e r s i s t P i x e l C a c h e                                         %
3996 %                                                                             %
3997 %                                                                             %
3998 %                                                                             %
3999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4000 %
4001 %  PersistPixelCache() attaches to or initializes a persistent pixel cache.  A
4002 %  persistent pixel cache is one that resides on disk and is not destroyed
4003 %  when the program exits.
4004 %
4005 %  The format of the PersistPixelCache() method is:
4006 %
4007 %      MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4008 %        const MagickBooleanType attach,MagickOffsetType *offset,
4009 %        ExceptionInfo *exception)
4010 %
4011 %  A description of each parameter follows:
4012 %
4013 %    o image: the image.
4014 %
4015 %    o filename: the persistent pixel cache filename.
4016 %
4017 %    o attach: A value other than zero initializes the persistent pixel cache.
4018 %
4019 %    o initialize: A value other than zero initializes the persistent pixel
4020 %      cache.
4021 %
4022 %    o offset: the offset in the persistent cache to store pixels.
4023 %
4024 %    o exception: return any errors or warnings in this structure.
4025 %
4026 */
PersistPixelCache(Image * image,const char * filename,const MagickBooleanType attach,MagickOffsetType * offset,ExceptionInfo * exception)4027 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4028   const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4029   ExceptionInfo *exception)
4030 {
4031   CacheInfo
4032     *magick_restrict cache_info,
4033     *magick_restrict clone_info;
4034 
4035   MagickBooleanType
4036     status;
4037 
4038   ssize_t
4039     page_size;
4040 
4041   assert(image != (Image *) NULL);
4042   assert(image->signature == MagickCoreSignature);
4043   if (image->debug != MagickFalse)
4044     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4045   assert(image->cache != (void *) NULL);
4046   assert(filename != (const char *) NULL);
4047   assert(offset != (MagickOffsetType *) NULL);
4048   page_size=GetMagickPageSize();
4049   cache_info=(CacheInfo *) image->cache;
4050   assert(cache_info->signature == MagickCoreSignature);
4051 #if defined(MAGICKCORE_OPENCL_SUPPORT)
4052   CopyOpenCLBuffer(cache_info);
4053 #endif
4054   if (attach != MagickFalse)
4055     {
4056       /*
4057         Attach existing persistent pixel cache.
4058       */
4059       if (image->debug != MagickFalse)
4060         (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4061           "attach persistent cache");
4062       (void) CopyMagickString(cache_info->cache_filename,filename,
4063         MagickPathExtent);
4064       cache_info->type=MapCache;
4065       cache_info->offset=(*offset);
4066       if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4067         return(MagickFalse);
4068       *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4069       return(MagickTrue);
4070     }
4071   /*
4072     Clone persistent pixel cache.
4073   */
4074   status=AcquireMagickResource(DiskResource,cache_info->length);
4075   if (status == MagickFalse)
4076     {
4077       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4078         "CacheResourcesExhausted","`%s'",image->filename);
4079       return(MagickFalse);
4080     }
4081   clone_info=(CacheInfo *) ClonePixelCache(cache_info);
4082   clone_info->type=DiskCache;
4083   (void) CopyMagickString(clone_info->cache_filename,filename,MagickPathExtent);
4084   clone_info->file=(-1);
4085   clone_info->storage_class=cache_info->storage_class;
4086   clone_info->colorspace=cache_info->colorspace;
4087   clone_info->alpha_trait=cache_info->alpha_trait;
4088   clone_info->channels=cache_info->channels;
4089   clone_info->columns=cache_info->columns;
4090   clone_info->rows=cache_info->rows;
4091   clone_info->number_channels=cache_info->number_channels;
4092   clone_info->metacontent_extent=cache_info->metacontent_extent;
4093   clone_info->mode=PersistMode;
4094   clone_info->length=cache_info->length;
4095   (void) memcpy(clone_info->channel_map,cache_info->channel_map,
4096     MaxPixelChannels*sizeof(*cache_info->channel_map));
4097   clone_info->offset=(*offset);
4098   status=ClonePixelCacheRepository(clone_info,cache_info,exception);
4099   *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4100   clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4101   return(status);
4102 }
4103 
4104 /*
4105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4106 %                                                                             %
4107 %                                                                             %
4108 %                                                                             %
4109 +   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                 %
4110 %                                                                             %
4111 %                                                                             %
4112 %                                                                             %
4113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4114 %
4115 %  QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4116 %  defined by the region rectangle and returns a pointer to the region.  This
4117 %  region is subsequently transferred from the pixel cache with
4118 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4119 %  pixels are transferred, otherwise a NULL is returned.
4120 %
4121 %  The format of the QueueAuthenticPixelCacheNexus() method is:
4122 %
4123 %      Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4124 %        const ssize_t y,const size_t columns,const size_t rows,
4125 %        const MagickBooleanType clone,NexusInfo *nexus_info,
4126 %        ExceptionInfo *exception)
4127 %
4128 %  A description of each parameter follows:
4129 %
4130 %    o image: the image.
4131 %
4132 %    o x,y,columns,rows:  These values define the perimeter of a region of
4133 %      pixels.
4134 %
4135 %    o nexus_info: the cache nexus to set.
4136 %
4137 %    o clone: clone the pixel cache.
4138 %
4139 %    o exception: return any errors or warnings in this structure.
4140 %
4141 */
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)4142 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4143   const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4144   const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4145 {
4146   CacheInfo
4147     *magick_restrict cache_info;
4148 
4149   MagickOffsetType
4150     offset;
4151 
4152   MagickSizeType
4153     number_pixels;
4154 
4155   Quantum
4156     *magick_restrict pixels;
4157 
4158   /*
4159     Validate pixel cache geometry.
4160   */
4161   assert(image != (const Image *) NULL);
4162   assert(image->signature == MagickCoreSignature);
4163   assert(image->cache != (Cache) NULL);
4164   cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4165   if (cache_info == (Cache) NULL)
4166     return((Quantum *) NULL);
4167   assert(cache_info->signature == MagickCoreSignature);
4168   if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
4169       (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4170       (y >= (ssize_t) cache_info->rows))
4171     {
4172       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4173         "PixelsAreNotAuthentic","`%s'",image->filename);
4174       return((Quantum *) NULL);
4175     }
4176   offset=(MagickOffsetType) y*cache_info->columns+x;
4177   if (offset < 0)
4178     return((Quantum *) NULL);
4179   number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4180   offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4181   if ((MagickSizeType) offset >= number_pixels)
4182     return((Quantum *) NULL);
4183   /*
4184     Return pixel cache.
4185   */
4186   pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,x,y,columns,rows,
4187     ((image->channels & WriteMaskChannel) != 0) ||
4188     ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
4189     nexus_info,exception);
4190   return(pixels);
4191 }
4192 
4193 /*
4194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4195 %                                                                             %
4196 %                                                                             %
4197 %                                                                             %
4198 +   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                         %
4199 %                                                                             %
4200 %                                                                             %
4201 %                                                                             %
4202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4203 %
4204 %  QueueAuthenticPixelsCache() allocates an region to store image pixels as
4205 %  defined by the region rectangle and returns a pointer to the region.  This
4206 %  region is subsequently transferred from the pixel cache with
4207 %  SyncAuthenticPixelsCache().  A pointer to the pixels is returned if the
4208 %  pixels are transferred, otherwise a NULL is returned.
4209 %
4210 %  The format of the QueueAuthenticPixelsCache() method is:
4211 %
4212 %      Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4213 %        const ssize_t y,const size_t columns,const size_t rows,
4214 %        ExceptionInfo *exception)
4215 %
4216 %  A description of each parameter follows:
4217 %
4218 %    o image: the image.
4219 %
4220 %    o x,y,columns,rows:  These values define the perimeter of a region of
4221 %      pixels.
4222 %
4223 %    o exception: return any errors or warnings in this structure.
4224 %
4225 */
QueueAuthenticPixelsCache(Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,ExceptionInfo * exception)4226 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4227   const ssize_t y,const size_t columns,const size_t rows,
4228   ExceptionInfo *exception)
4229 {
4230   CacheInfo
4231     *magick_restrict cache_info;
4232 
4233   const int
4234     id = GetOpenMPThreadId();
4235 
4236   Quantum
4237     *magick_restrict pixels;
4238 
4239   assert(image != (const Image *) NULL);
4240   assert(image->signature == MagickCoreSignature);
4241   assert(image->cache != (Cache) NULL);
4242   cache_info=(CacheInfo *) image->cache;
4243   assert(cache_info->signature == MagickCoreSignature);
4244   assert(id < (int) cache_info->number_threads);
4245   pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4246     cache_info->nexus_info[id],exception);
4247   return(pixels);
4248 }
4249 
4250 /*
4251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4252 %                                                                             %
4253 %                                                                             %
4254 %                                                                             %
4255 %   Q u e u e A u t h e n t i c P i x e l s                                   %
4256 %                                                                             %
4257 %                                                                             %
4258 %                                                                             %
4259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4260 %
4261 %  QueueAuthenticPixels() queues a mutable pixel region.  If the region is
4262 %  successfully initialized a pointer to a Quantum array representing the
4263 %  region is returned, otherwise NULL is returned.  The returned pointer may
4264 %  point to a temporary working buffer for the pixels or it may point to the
4265 %  final location of the pixels in memory.
4266 %
4267 %  Write-only access means that any existing pixel values corresponding to
4268 %  the region are ignored.  This is useful if the initial image is being
4269 %  created from scratch, or if the existing pixel values are to be
4270 %  completely replaced without need to refer to their pre-existing values.
4271 %  The application is free to read and write the pixel buffer returned by
4272 %  QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4273 %  initialize the pixel array values. Initializing pixel array values is the
4274 %  application's responsibility.
4275 %
4276 %  Performance is maximized if the selected region is part of one row, or
4277 %  one or more full rows, since then there is opportunity to access the
4278 %  pixels in-place (without a copy) if the image is in memory, or in a
4279 %  memory-mapped file. The returned pointer must *never* be deallocated
4280 %  by the user.
4281 %
4282 %  Pixels accessed via the returned pointer represent a simple array of type
4283 %  Quantum. If the image type is CMYK or the storage class is PseudoClass,
4284 %  call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4285 %  obtain the meta-content (of type void) corresponding to the region.
4286 %  Once the Quantum (and/or Quantum) array has been updated, the
4287 %  changes must be saved back to the underlying image using
4288 %  SyncAuthenticPixels() or they may be lost.
4289 %
4290 %  The format of the QueueAuthenticPixels() method is:
4291 %
4292 %      Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4293 %        const ssize_t y,const size_t columns,const size_t rows,
4294 %        ExceptionInfo *exception)
4295 %
4296 %  A description of each parameter follows:
4297 %
4298 %    o image: the image.
4299 %
4300 %    o x,y,columns,rows:  These values define the perimeter of a region of
4301 %      pixels.
4302 %
4303 %    o exception: return any errors or warnings in this structure.
4304 %
4305 */
QueueAuthenticPixels(Image * image,const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,ExceptionInfo * exception)4306 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4307   const ssize_t y,const size_t columns,const size_t rows,
4308   ExceptionInfo *exception)
4309 {
4310   CacheInfo
4311     *magick_restrict cache_info;
4312 
4313   const int
4314     id = GetOpenMPThreadId();
4315 
4316   Quantum
4317     *magick_restrict pixels;
4318 
4319   assert(image != (Image *) NULL);
4320   assert(image->signature == MagickCoreSignature);
4321   assert(image->cache != (Cache) NULL);
4322   cache_info=(CacheInfo *) image->cache;
4323   assert(cache_info->signature == MagickCoreSignature);
4324   if (cache_info->methods.queue_authentic_pixels_handler !=
4325       (QueueAuthenticPixelsHandler) NULL)
4326     {
4327       pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4328         columns,rows,exception);
4329       return(pixels);
4330     }
4331   assert(id < (int) cache_info->number_threads);
4332   pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4333     cache_info->nexus_info[id],exception);
4334   return(pixels);
4335 }
4336 
4337 /*
4338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4339 %                                                                             %
4340 %                                                                             %
4341 %                                                                             %
4342 +   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                         %
4343 %                                                                             %
4344 %                                                                             %
4345 %                                                                             %
4346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4347 %
4348 %  ReadPixelCacheMetacontent() reads metacontent from the specified region of
4349 %  the pixel cache.
4350 %
4351 %  The format of the ReadPixelCacheMetacontent() method is:
4352 %
4353 %      MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4354 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4355 %
4356 %  A description of each parameter follows:
4357 %
4358 %    o cache_info: the pixel cache.
4359 %
4360 %    o nexus_info: the cache nexus to read the metacontent.
4361 %
4362 %    o exception: return any errors or warnings in this structure.
4363 %
4364 */
4365 
ReadPixelCacheRegion(const CacheInfo * magick_restrict cache_info,const MagickOffsetType offset,const MagickSizeType length,unsigned char * magick_restrict buffer)4366 static inline MagickOffsetType ReadPixelCacheRegion(
4367   const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4368   const MagickSizeType length,unsigned char *magick_restrict buffer)
4369 {
4370   MagickOffsetType
4371     i;
4372 
4373   ssize_t
4374     count;
4375 
4376 #if !defined(MAGICKCORE_HAVE_PREAD)
4377   if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4378     return((MagickOffsetType) -1);
4379 #endif
4380   count=0;
4381   for (i=0; i < (MagickOffsetType) length; i+=count)
4382   {
4383 #if !defined(MAGICKCORE_HAVE_PREAD)
4384     count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4385       MAGICK_SSIZE_MAX));
4386 #else
4387     count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4388       MAGICK_SSIZE_MAX),offset+i);
4389 #endif
4390     if (count <= 0)
4391       {
4392         count=0;
4393         if (errno != EINTR)
4394           break;
4395       }
4396   }
4397   return(i);
4398 }
4399 
ReadPixelCacheMetacontent(CacheInfo * magick_restrict cache_info,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)4400 static MagickBooleanType ReadPixelCacheMetacontent(
4401   CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4402   ExceptionInfo *exception)
4403 {
4404   MagickOffsetType
4405     count,
4406     offset;
4407 
4408   MagickSizeType
4409     extent,
4410     length;
4411 
4412   ssize_t
4413     y;
4414 
4415   unsigned char
4416     *magick_restrict q;
4417 
4418   size_t
4419     rows;
4420 
4421   if (cache_info->metacontent_extent == 0)
4422     return(MagickFalse);
4423   if (nexus_info->authentic_pixel_cache != MagickFalse)
4424     return(MagickTrue);
4425   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4426     nexus_info->region.x;
4427   length=(MagickSizeType) nexus_info->region.width*
4428     cache_info->metacontent_extent;
4429   extent=length*nexus_info->region.height;
4430   rows=nexus_info->region.height;
4431   y=0;
4432   q=(unsigned char *) nexus_info->metacontent;
4433   switch (cache_info->type)
4434   {
4435     case MemoryCache:
4436     case MapCache:
4437     {
4438       unsigned char
4439         *magick_restrict p;
4440 
4441       /*
4442         Read meta-content from memory.
4443       */
4444       if ((cache_info->columns == nexus_info->region.width) &&
4445           (extent == (MagickSizeType) ((size_t) extent)))
4446         {
4447           length=extent;
4448           rows=1UL;
4449         }
4450       p=(unsigned char *) cache_info->metacontent+offset*
4451         cache_info->metacontent_extent;
4452       for (y=0; y < (ssize_t) rows; y++)
4453       {
4454         (void) memcpy(q,p,(size_t) length);
4455         p+=cache_info->metacontent_extent*cache_info->columns;
4456         q+=cache_info->metacontent_extent*nexus_info->region.width;
4457       }
4458       break;
4459     }
4460     case DiskCache:
4461     {
4462       /*
4463         Read meta content from disk.
4464       */
4465       LockSemaphoreInfo(cache_info->file_semaphore);
4466       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4467         {
4468           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4469             cache_info->cache_filename);
4470           UnlockSemaphoreInfo(cache_info->file_semaphore);
4471           return(MagickFalse);
4472         }
4473       if ((cache_info->columns == nexus_info->region.width) &&
4474           (extent <= MagickMaxBufferExtent))
4475         {
4476           length=extent;
4477           rows=1UL;
4478         }
4479       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4480       for (y=0; y < (ssize_t) rows; y++)
4481       {
4482         count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4483           cache_info->number_channels*sizeof(Quantum)+offset*
4484           cache_info->metacontent_extent,length,(unsigned char *) q);
4485         if (count != (MagickOffsetType) length)
4486           break;
4487         offset+=cache_info->columns;
4488         q+=cache_info->metacontent_extent*nexus_info->region.width;
4489       }
4490       if (IsFileDescriptorLimitExceeded() != MagickFalse)
4491         (void) ClosePixelCacheOnDisk(cache_info);
4492       UnlockSemaphoreInfo(cache_info->file_semaphore);
4493       break;
4494     }
4495     case DistributedCache:
4496     {
4497       RectangleInfo
4498         region;
4499 
4500       /*
4501         Read metacontent from distributed cache.
4502       */
4503       LockSemaphoreInfo(cache_info->file_semaphore);
4504       region=nexus_info->region;
4505       if ((cache_info->columns != nexus_info->region.width) ||
4506           (extent > MagickMaxBufferExtent))
4507         region.height=1UL;
4508       else
4509         {
4510           length=extent;
4511           rows=1UL;
4512         }
4513       for (y=0; y < (ssize_t) rows; y++)
4514       {
4515         count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4516           cache_info->server_info,&region,length,(unsigned char *) q);
4517         if (count != (MagickOffsetType) length)
4518           break;
4519         q+=cache_info->metacontent_extent*nexus_info->region.width;
4520         region.y++;
4521       }
4522       UnlockSemaphoreInfo(cache_info->file_semaphore);
4523       break;
4524     }
4525     default:
4526       break;
4527   }
4528   if (y < (ssize_t) rows)
4529     {
4530       ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4531         cache_info->cache_filename);
4532       return(MagickFalse);
4533     }
4534   if ((cache_info->debug != MagickFalse) &&
4535       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4536     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4537       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4538       nexus_info->region.width,(double) nexus_info->region.height,(double)
4539       nexus_info->region.x,(double) nexus_info->region.y);
4540   return(MagickTrue);
4541 }
4542 
4543 /*
4544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4545 %                                                                             %
4546 %                                                                             %
4547 %                                                                             %
4548 +   R e a d P i x e l C a c h e P i x e l s                                   %
4549 %                                                                             %
4550 %                                                                             %
4551 %                                                                             %
4552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4553 %
4554 %  ReadPixelCachePixels() reads pixels from the specified region of the pixel
4555 %  cache.
4556 %
4557 %  The format of the ReadPixelCachePixels() method is:
4558 %
4559 %      MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4560 %        NexusInfo *nexus_info,ExceptionInfo *exception)
4561 %
4562 %  A description of each parameter follows:
4563 %
4564 %    o cache_info: the pixel cache.
4565 %
4566 %    o nexus_info: the cache nexus to read the pixels.
4567 %
4568 %    o exception: return any errors or warnings in this structure.
4569 %
4570 */
ReadPixelCachePixels(CacheInfo * magick_restrict cache_info,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)4571 static MagickBooleanType ReadPixelCachePixels(
4572   CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4573   ExceptionInfo *exception)
4574 {
4575   MagickOffsetType
4576     count,
4577     offset;
4578 
4579   MagickSizeType
4580     extent,
4581     length;
4582 
4583   Quantum
4584     *magick_restrict q;
4585 
4586   ssize_t
4587     y;
4588 
4589   size_t
4590     number_channels,
4591     rows;
4592 
4593   if (nexus_info->authentic_pixel_cache != MagickFalse)
4594     return(MagickTrue);
4595   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns;
4596   if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4597     return(MagickFalse);
4598   offset+=nexus_info->region.x;
4599   number_channels=cache_info->number_channels;
4600   length=(MagickSizeType) number_channels*nexus_info->region.width*
4601     sizeof(Quantum);
4602   if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4603     return(MagickFalse);
4604   rows=nexus_info->region.height;
4605   extent=length*rows;
4606   if ((extent == 0) || ((extent/length) != rows))
4607     return(MagickFalse);
4608   y=0;
4609   q=nexus_info->pixels;
4610   switch (cache_info->type)
4611   {
4612     case MemoryCache:
4613     case MapCache:
4614     {
4615       Quantum
4616         *magick_restrict p;
4617 
4618       /*
4619         Read pixels from memory.
4620       */
4621       if ((cache_info->columns == nexus_info->region.width) &&
4622           (extent == (MagickSizeType) ((size_t) extent)))
4623         {
4624           length=extent;
4625           rows=1UL;
4626         }
4627       p=cache_info->pixels+cache_info->number_channels*offset;
4628       for (y=0; y < (ssize_t) rows; y++)
4629       {
4630         (void) memcpy(q,p,(size_t) length);
4631         p+=cache_info->number_channels*cache_info->columns;
4632         q+=cache_info->number_channels*nexus_info->region.width;
4633       }
4634       break;
4635     }
4636     case DiskCache:
4637     {
4638       /*
4639         Read pixels from disk.
4640       */
4641       LockSemaphoreInfo(cache_info->file_semaphore);
4642       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4643         {
4644           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4645             cache_info->cache_filename);
4646           UnlockSemaphoreInfo(cache_info->file_semaphore);
4647           return(MagickFalse);
4648         }
4649       if ((cache_info->columns == nexus_info->region.width) &&
4650           (extent <= MagickMaxBufferExtent))
4651         {
4652           length=extent;
4653           rows=1UL;
4654         }
4655       for (y=0; y < (ssize_t) rows; y++)
4656       {
4657         count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4658           cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4659         if (count != (MagickOffsetType) length)
4660           break;
4661         offset+=cache_info->columns;
4662         q+=cache_info->number_channels*nexus_info->region.width;
4663       }
4664       if (IsFileDescriptorLimitExceeded() != MagickFalse)
4665         (void) ClosePixelCacheOnDisk(cache_info);
4666       UnlockSemaphoreInfo(cache_info->file_semaphore);
4667       break;
4668     }
4669     case DistributedCache:
4670     {
4671       RectangleInfo
4672         region;
4673 
4674       /*
4675         Read pixels from distributed cache.
4676       */
4677       LockSemaphoreInfo(cache_info->file_semaphore);
4678       region=nexus_info->region;
4679       if ((cache_info->columns != nexus_info->region.width) ||
4680           (extent > MagickMaxBufferExtent))
4681         region.height=1UL;
4682       else
4683         {
4684           length=extent;
4685           rows=1UL;
4686         }
4687       for (y=0; y < (ssize_t) rows; y++)
4688       {
4689         count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4690           cache_info->server_info,&region,length,(unsigned char *) q);
4691         if (count != (MagickOffsetType) length)
4692           break;
4693         q+=cache_info->number_channels*nexus_info->region.width;
4694         region.y++;
4695       }
4696       UnlockSemaphoreInfo(cache_info->file_semaphore);
4697       break;
4698     }
4699     default:
4700       break;
4701   }
4702   if (y < (ssize_t) rows)
4703     {
4704       ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4705         cache_info->cache_filename);
4706       return(MagickFalse);
4707     }
4708   if ((cache_info->debug != MagickFalse) &&
4709       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4710     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4711       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4712       nexus_info->region.width,(double) nexus_info->region.height,(double)
4713       nexus_info->region.x,(double) nexus_info->region.y);
4714   return(MagickTrue);
4715 }
4716 
4717 /*
4718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4719 %                                                                             %
4720 %                                                                             %
4721 %                                                                             %
4722 +   R e f e r e n c e P i x e l C a c h e                                     %
4723 %                                                                             %
4724 %                                                                             %
4725 %                                                                             %
4726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4727 %
4728 %  ReferencePixelCache() increments the reference count associated with the
4729 %  pixel cache returning a pointer to the cache.
4730 %
4731 %  The format of the ReferencePixelCache method is:
4732 %
4733 %      Cache ReferencePixelCache(Cache cache_info)
4734 %
4735 %  A description of each parameter follows:
4736 %
4737 %    o cache_info: the pixel cache.
4738 %
4739 */
ReferencePixelCache(Cache cache)4740 MagickPrivate Cache ReferencePixelCache(Cache cache)
4741 {
4742   CacheInfo
4743     *magick_restrict cache_info;
4744 
4745   assert(cache != (Cache *) NULL);
4746   cache_info=(CacheInfo *) cache;
4747   assert(cache_info->signature == MagickCoreSignature);
4748   LockSemaphoreInfo(cache_info->semaphore);
4749   cache_info->reference_count++;
4750   UnlockSemaphoreInfo(cache_info->semaphore);
4751   return(cache_info);
4752 }
4753 
4754 /*
4755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4756 %                                                                             %
4757 %                                                                             %
4758 %                                                                             %
4759 +   R e s e t P i x e l C a c h e C h a n n e l s                             %
4760 %                                                                             %
4761 %                                                                             %
4762 %                                                                             %
4763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4764 %
4765 %  ResetPixelCacheChannels() resets the pixel cache channels.
4766 %
4767 %  The format of the ResetPixelCacheChannels method is:
4768 %
4769 %      void ResetPixelCacheChannels(Image *)
4770 %
4771 %  A description of each parameter follows:
4772 %
4773 %    o image: the image.
4774 %
4775 */
ResetPixelCacheChannels(Image * image)4776 MagickPrivate void ResetPixelCacheChannels(Image *image)
4777 {
4778   CacheInfo
4779     *magick_restrict cache_info;
4780 
4781   assert(image != (const Image *) NULL);
4782   assert(image->signature == MagickCoreSignature);
4783   assert(image->cache != (Cache) NULL);
4784   cache_info=(CacheInfo *) image->cache;
4785   assert(cache_info->signature == MagickCoreSignature);
4786   cache_info->number_channels=GetPixelChannels(image);
4787 }
4788 
4789 /*
4790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4791 %                                                                             %
4792 %                                                                             %
4793 %                                                                             %
4794 +   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                         %
4795 %                                                                             %
4796 %                                                                             %
4797 %                                                                             %
4798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4799 %
4800 %  ResetCacheAnonymousMemory() resets the anonymous_memory value.
4801 %
4802 %  The format of the ResetCacheAnonymousMemory method is:
4803 %
4804 %      void ResetCacheAnonymousMemory(void)
4805 %
4806 */
ResetCacheAnonymousMemory(void)4807 MagickPrivate void ResetCacheAnonymousMemory(void)
4808 {
4809   cache_anonymous_memory=0;
4810 }
4811 
4812 /*
4813 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4814 %                                                                             %
4815 %                                                                             %
4816 %                                                                             %
4817 +   R e s e t P i x e l C a c h e E p o c h                                   %
4818 %                                                                             %
4819 %                                                                             %
4820 %                                                                             %
4821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4822 %
4823 %  ResetPixelCacheEpoch() resets the pixel cache epoch.
4824 %
4825 %  The format of the ResetPixelCacheEpoch method is:
4826 %
4827 %      void ResetPixelCacheEpoch(void)
4828 %
4829 */
ResetPixelCacheEpoch(void)4830 MagickPrivate void ResetPixelCacheEpoch(void)
4831 {
4832   cache_epoch=0;
4833 }
4834 
4835 /*
4836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4837 %                                                                             %
4838 %                                                                             %
4839 %                                                                             %
4840 +   S e t P i x e l C a c h e M e t h o d s                                   %
4841 %                                                                             %
4842 %                                                                             %
4843 %                                                                             %
4844 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4845 %
4846 %  SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4847 %
4848 %  The format of the SetPixelCacheMethods() method is:
4849 %
4850 %      SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4851 %
4852 %  A description of each parameter follows:
4853 %
4854 %    o cache: the pixel cache.
4855 %
4856 %    o cache_methods: Specifies a pointer to a CacheMethods structure.
4857 %
4858 */
SetPixelCacheMethods(Cache cache,CacheMethods * cache_methods)4859 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4860 {
4861   CacheInfo
4862     *magick_restrict cache_info;
4863 
4864   GetOneAuthenticPixelFromHandler
4865     get_one_authentic_pixel_from_handler;
4866 
4867   GetOneVirtualPixelFromHandler
4868     get_one_virtual_pixel_from_handler;
4869 
4870   /*
4871     Set cache pixel methods.
4872   */
4873   assert(cache != (Cache) NULL);
4874   assert(cache_methods != (CacheMethods *) NULL);
4875   cache_info=(CacheInfo *) cache;
4876   assert(cache_info->signature == MagickCoreSignature);
4877   if (cache_info->debug != MagickFalse)
4878     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4879       cache_info->filename);
4880   if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4881     cache_info->methods.get_virtual_pixel_handler=
4882       cache_methods->get_virtual_pixel_handler;
4883   if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4884     cache_info->methods.destroy_pixel_handler=
4885       cache_methods->destroy_pixel_handler;
4886   if (cache_methods->get_virtual_metacontent_from_handler !=
4887       (GetVirtualMetacontentFromHandler) NULL)
4888     cache_info->methods.get_virtual_metacontent_from_handler=
4889       cache_methods->get_virtual_metacontent_from_handler;
4890   if (cache_methods->get_authentic_pixels_handler !=
4891       (GetAuthenticPixelsHandler) NULL)
4892     cache_info->methods.get_authentic_pixels_handler=
4893       cache_methods->get_authentic_pixels_handler;
4894   if (cache_methods->queue_authentic_pixels_handler !=
4895       (QueueAuthenticPixelsHandler) NULL)
4896     cache_info->methods.queue_authentic_pixels_handler=
4897       cache_methods->queue_authentic_pixels_handler;
4898   if (cache_methods->sync_authentic_pixels_handler !=
4899       (SyncAuthenticPixelsHandler) NULL)
4900     cache_info->methods.sync_authentic_pixels_handler=
4901       cache_methods->sync_authentic_pixels_handler;
4902   if (cache_methods->get_authentic_pixels_from_handler !=
4903       (GetAuthenticPixelsFromHandler) NULL)
4904     cache_info->methods.get_authentic_pixels_from_handler=
4905       cache_methods->get_authentic_pixels_from_handler;
4906   if (cache_methods->get_authentic_metacontent_from_handler !=
4907       (GetAuthenticMetacontentFromHandler) NULL)
4908     cache_info->methods.get_authentic_metacontent_from_handler=
4909       cache_methods->get_authentic_metacontent_from_handler;
4910   get_one_virtual_pixel_from_handler=
4911     cache_info->methods.get_one_virtual_pixel_from_handler;
4912   if (get_one_virtual_pixel_from_handler !=
4913       (GetOneVirtualPixelFromHandler) NULL)
4914     cache_info->methods.get_one_virtual_pixel_from_handler=
4915       cache_methods->get_one_virtual_pixel_from_handler;
4916   get_one_authentic_pixel_from_handler=
4917     cache_methods->get_one_authentic_pixel_from_handler;
4918   if (get_one_authentic_pixel_from_handler !=
4919       (GetOneAuthenticPixelFromHandler) NULL)
4920     cache_info->methods.get_one_authentic_pixel_from_handler=
4921       cache_methods->get_one_authentic_pixel_from_handler;
4922 }
4923 
4924 /*
4925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4926 %                                                                             %
4927 %                                                                             %
4928 %                                                                             %
4929 +   S e t P i x e l C a c h e N e x u s P i x e l s                           %
4930 %                                                                             %
4931 %                                                                             %
4932 %                                                                             %
4933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4934 %
4935 %  SetPixelCacheNexusPixels() defines the region of the cache for the
4936 %  specified cache nexus.
4937 %
4938 %  The format of the SetPixelCacheNexusPixels() method is:
4939 %
4940 %      Quantum SetPixelCacheNexusPixels(
4941 %        const CacheInfo *magick_restrict cache_info,const MapMode mode,
4942 %        const ssize_t x,const ssize_t y,const size_t width,const size_t height,
4943 %        const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
4944 %        ExceptionInfo *exception)
4945 %
4946 %  A description of each parameter follows:
4947 %
4948 %    o cache_info: the pixel cache.
4949 %
4950 %    o mode: ReadMode, WriteMode, or IOMode.
4951 %
4952 %    o x,y,width,height: define the region of this particular cache nexus.
4953 %
4954 %    o buffered: if true, nexus pixels are buffered.
4955 %
4956 %    o nexus_info: the cache nexus to set.
4957 %
4958 %    o exception: return any errors or warnings in this structure.
4959 %
4960 */
4961 
AcquireCacheNexusPixels(const CacheInfo * magick_restrict cache_info,const MagickSizeType length,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)4962 static inline MagickBooleanType AcquireCacheNexusPixels(
4963   const CacheInfo *magick_restrict cache_info,const MagickSizeType length,
4964   NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
4965 {
4966   if (length != (MagickSizeType) ((size_t) length))
4967     {
4968       (void) ThrowMagickException(exception,GetMagickModule(),
4969         ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
4970         cache_info->filename);
4971       return(MagickFalse);
4972     }
4973   nexus_info->length=0;
4974   nexus_info->mapped=MagickFalse;
4975   if (cache_anonymous_memory <= 0)
4976     {
4977       nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4978         (size_t) length));
4979       if (nexus_info->cache != (Quantum *) NULL)
4980         (void) memset(nexus_info->cache,0,(size_t) length);
4981     }
4982   else
4983     {
4984       nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t) length);
4985       if (nexus_info->cache != (Quantum *) NULL)
4986         nexus_info->mapped=MagickTrue;
4987     }
4988   if (nexus_info->cache == (Quantum *) NULL)
4989     {
4990       (void) ThrowMagickException(exception,GetMagickModule(),
4991         ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
4992         cache_info->filename);
4993       return(MagickFalse);
4994     }
4995   nexus_info->length=length;
4996   return(MagickTrue);
4997 }
4998 
PrefetchPixelCacheNexusPixels(const NexusInfo * nexus_info,const MapMode mode)4999 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
5000   const MapMode mode)
5001 {
5002   if (nexus_info->length < CACHE_LINE_SIZE)
5003     return;
5004   if (mode == ReadMode)
5005     {
5006       MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,
5007         0,1);
5008       return;
5009     }
5010   MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,1,1);
5011 }
5012 
ValidatePixelOffset(const ssize_t x,const size_t a)5013 static inline MagickBooleanType ValidatePixelOffset(const ssize_t x,
5014   const size_t a)
5015 {
5016   if ((x >= 0) && (x >= ((ssize_t) MAGICK_SSIZE_MAX-(ssize_t) a)))
5017     return(MagickFalse);
5018   if (x <= ((ssize_t) MAGICK_SSIZE_MIN+(ssize_t) a))
5019     return(MagickFalse);
5020   return(MagickTrue);
5021 }
5022 
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)5023 static Quantum *SetPixelCacheNexusPixels(
5024   const CacheInfo *magick_restrict cache_info,const MapMode mode,
5025   const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5026   const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5027   ExceptionInfo *exception)
5028 {
5029   MagickBooleanType
5030     status;
5031 
5032   MagickSizeType
5033     length,
5034     number_pixels;
5035 
5036   assert(cache_info != (const CacheInfo *) NULL);
5037   assert(cache_info->signature == MagickCoreSignature);
5038   if (cache_info->type == UndefinedCache)
5039     return((Quantum *) NULL);
5040   assert(nexus_info->signature == MagickCoreSignature);
5041   (void) memset(&nexus_info->region,0,sizeof(nexus_info->region));
5042   if ((width == 0) || (height == 0))
5043     {
5044       (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
5045         "NoPixelsDefinedInCache","`%s'",cache_info->filename);
5046       return((Quantum *) NULL);
5047     }
5048   if (((MagickSizeType) width > cache_info->width_limit) ||
5049       ((MagickSizeType) height > cache_info->height_limit) ||
5050       (ValidatePixelOffset(x,width) == MagickFalse) ||
5051       (ValidatePixelOffset(y,height) == MagickFalse))
5052     {
5053       (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
5054         "WidthOrHeightExceedsLimit","`%s'",cache_info->filename);
5055       return((Quantum *) NULL);
5056     }
5057   if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
5058       (buffered == MagickFalse))
5059     {
5060       if (((x >= 0) && (y >= 0) &&
5061           (((ssize_t) height+y-1) < (ssize_t) cache_info->rows)) &&
5062           (((x == 0) && (width == cache_info->columns)) || ((height == 1) &&
5063           (((ssize_t) width+x-1) < (ssize_t) cache_info->columns))))
5064         {
5065           MagickOffsetType
5066             offset;
5067 
5068           /*
5069             Pixels are accessed directly from memory.
5070           */
5071           offset=(MagickOffsetType) y*cache_info->columns+x;
5072           nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5073             offset;
5074           nexus_info->metacontent=(void *) NULL;
5075           if (cache_info->metacontent_extent != 0)
5076             nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5077               offset*cache_info->metacontent_extent;
5078           nexus_info->region.width=width;
5079           nexus_info->region.height=height;
5080           nexus_info->region.x=x;
5081           nexus_info->region.y=y;
5082           nexus_info->authentic_pixel_cache=MagickTrue;
5083           PrefetchPixelCacheNexusPixels(nexus_info,mode);
5084           return(nexus_info->pixels);
5085         }
5086     }
5087   /*
5088     Pixels are stored in a staging region until they are synced to the cache.
5089   */
5090   number_pixels=(MagickSizeType) width*height;
5091   length=MagickMax(number_pixels,MagickMax(cache_info->columns,
5092     cache_info->rows))*cache_info->number_channels*sizeof(*nexus_info->pixels);
5093   if (cache_info->metacontent_extent != 0)
5094     length+=number_pixels*cache_info->metacontent_extent;
5095   status=MagickTrue;
5096   if (nexus_info->cache == (Quantum *) NULL)
5097     status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5098   else
5099     if (nexus_info->length < length)
5100       {
5101         RelinquishCacheNexusPixels(nexus_info);
5102         status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5103       }
5104   if (status == MagickFalse)
5105     return((Quantum *) NULL);
5106   nexus_info->pixels=nexus_info->cache;
5107   nexus_info->metacontent=(void *) NULL;
5108   if (cache_info->metacontent_extent != 0)
5109     nexus_info->metacontent=(void *) (nexus_info->pixels+
5110       cache_info->number_channels*number_pixels);
5111   nexus_info->region.width=width;
5112   nexus_info->region.height=height;
5113   nexus_info->region.x=x;
5114   nexus_info->region.y=y;
5115   nexus_info->authentic_pixel_cache=cache_info->type == PingCache ?
5116     MagickTrue : MagickFalse;
5117   PrefetchPixelCacheNexusPixels(nexus_info,mode);
5118   return(nexus_info->pixels);
5119 }
5120 
5121 /*
5122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5123 %                                                                             %
5124 %                                                                             %
5125 %                                                                             %
5126 %   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                       %
5127 %                                                                             %
5128 %                                                                             %
5129 %                                                                             %
5130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5131 %
5132 %  SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5133 %  pixel cache and returns the previous setting.  A virtual pixel is any pixel
5134 %  access that is outside the boundaries of the image cache.
5135 %
5136 %  The format of the SetPixelCacheVirtualMethod() method is:
5137 %
5138 %      VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5139 %        const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5140 %
5141 %  A description of each parameter follows:
5142 %
5143 %    o image: the image.
5144 %
5145 %    o virtual_pixel_method: choose the type of virtual pixel.
5146 %
5147 %    o exception: return any errors or warnings in this structure.
5148 %
5149 */
5150 
SetCacheAlphaChannel(Image * image,const Quantum alpha,ExceptionInfo * exception)5151 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
5152   ExceptionInfo *exception)
5153 {
5154   CacheInfo
5155     *magick_restrict cache_info;
5156 
5157   CacheView
5158     *magick_restrict image_view;
5159 
5160   MagickBooleanType
5161     status;
5162 
5163   ssize_t
5164     y;
5165 
5166   assert(image != (Image *) NULL);
5167   assert(image->signature == MagickCoreSignature);
5168   if (image->debug != MagickFalse)
5169     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5170   assert(image->cache != (Cache) NULL);
5171   cache_info=(CacheInfo *) image->cache;
5172   assert(cache_info->signature == MagickCoreSignature);
5173   image->alpha_trait=BlendPixelTrait;
5174   status=MagickTrue;
5175   image_view=AcquireVirtualCacheView(image,exception);  /* must be virtual */
5176 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5177   #pragma omp parallel for schedule(static) shared(status) \
5178     magick_number_threads(image,image,image->rows,1)
5179 #endif
5180   for (y=0; y < (ssize_t) image->rows; y++)
5181   {
5182     Quantum
5183       *magick_restrict q;
5184 
5185     ssize_t
5186       x;
5187 
5188     if (status == MagickFalse)
5189       continue;
5190     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5191     if (q == (Quantum *) NULL)
5192       {
5193         status=MagickFalse;
5194         continue;
5195       }
5196     for (x=0; x < (ssize_t) image->columns; x++)
5197     {
5198       SetPixelAlpha(image,alpha,q);
5199       q+=GetPixelChannels(image);
5200     }
5201     status=SyncCacheViewAuthenticPixels(image_view,exception);
5202   }
5203   image_view=DestroyCacheView(image_view);
5204   return(status);
5205 }
5206 
SetPixelCacheVirtualMethod(Image * image,const VirtualPixelMethod virtual_pixel_method,ExceptionInfo * exception)5207 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5208   const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5209 {
5210   CacheInfo
5211     *magick_restrict cache_info;
5212 
5213   VirtualPixelMethod
5214     method;
5215 
5216   assert(image != (Image *) NULL);
5217   assert(image->signature == MagickCoreSignature);
5218   if (image->debug != MagickFalse)
5219     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5220   assert(image->cache != (Cache) NULL);
5221   cache_info=(CacheInfo *) image->cache;
5222   assert(cache_info->signature == MagickCoreSignature);
5223   method=cache_info->virtual_pixel_method;
5224   cache_info->virtual_pixel_method=virtual_pixel_method;
5225   if ((image->columns != 0) && (image->rows != 0))
5226     switch (virtual_pixel_method)
5227     {
5228       case BackgroundVirtualPixelMethod:
5229       {
5230         if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
5231             (image->alpha_trait == UndefinedPixelTrait))
5232           (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5233         if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
5234             (IsGrayColorspace(image->colorspace) != MagickFalse))
5235           (void) SetImageColorspace(image,sRGBColorspace,exception);
5236         break;
5237       }
5238       case TransparentVirtualPixelMethod:
5239       {
5240         if (image->alpha_trait == UndefinedPixelTrait)
5241           (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5242         break;
5243       }
5244       default:
5245         break;
5246     }
5247   return(method);
5248 }
5249 
5250 #if defined(MAGICKCORE_OPENCL_SUPPORT)
5251 /*
5252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5253 %                                                                             %
5254 %                                                                             %
5255 %                                                                             %
5256 +   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                         %
5257 %                                                                             %
5258 %                                                                             %
5259 %                                                                             %
5260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5261 %
5262 %  SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
5263 %  been completed and updates the host memory.
5264 %
5265 %  The format of the SyncAuthenticOpenCLBuffer() method is:
5266 %
5267 %      void SyncAuthenticOpenCLBuffer(const Image *image)
5268 %
5269 %  A description of each parameter follows:
5270 %
5271 %    o image: the image.
5272 %
5273 */
5274 
CopyOpenCLBuffer(CacheInfo * magick_restrict cache_info)5275 static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5276 {
5277   assert(cache_info != (CacheInfo *) NULL);
5278   assert(cache_info->signature == MagickCoreSignature);
5279   if ((cache_info->type != MemoryCache) ||
5280       (cache_info->opencl == (MagickCLCacheInfo) NULL))
5281     return;
5282   /*
5283     Ensure single threaded access to OpenCL environment.
5284   */
5285   LockSemaphoreInfo(cache_info->semaphore);
5286   cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
5287   UnlockSemaphoreInfo(cache_info->semaphore);
5288 }
5289 
SyncAuthenticOpenCLBuffer(const Image * image)5290 MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5291 {
5292   CacheInfo
5293     *magick_restrict cache_info;
5294 
5295   assert(image != (const Image *) NULL);
5296   cache_info=(CacheInfo *) image->cache;
5297   CopyOpenCLBuffer(cache_info);
5298 }
5299 #endif
5300 
5301 /*
5302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5303 %                                                                             %
5304 %                                                                             %
5305 %                                                                             %
5306 +   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                   %
5307 %                                                                             %
5308 %                                                                             %
5309 %                                                                             %
5310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5311 %
5312 %  SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5313 %  in-memory or disk cache.  The method returns MagickTrue if the pixel region
5314 %  is synced, otherwise MagickFalse.
5315 %
5316 %  The format of the SyncAuthenticPixelCacheNexus() method is:
5317 %
5318 %      MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5319 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5320 %
5321 %  A description of each parameter follows:
5322 %
5323 %    o image: the image.
5324 %
5325 %    o nexus_info: the cache nexus to sync.
5326 %
5327 %    o exception: return any errors or warnings in this structure.
5328 %
5329 */
SyncAuthenticPixelCacheNexus(Image * image,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)5330 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5331   NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5332 {
5333   CacheInfo
5334     *magick_restrict cache_info;
5335 
5336   MagickBooleanType
5337     status;
5338 
5339   /*
5340     Transfer pixels to the cache.
5341   */
5342   assert(image != (Image *) NULL);
5343   assert(image->signature == MagickCoreSignature);
5344   if (image->cache == (Cache) NULL)
5345     ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5346   cache_info=(CacheInfo *) image->cache;
5347   assert(cache_info->signature == MagickCoreSignature);
5348   if (cache_info->type == UndefinedCache)
5349     return(MagickFalse);
5350   if (image->mask_trait != UpdatePixelTrait)
5351     {
5352       if (((image->channels & WriteMaskChannel) != 0) &&
5353           (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5354         return(MagickFalse);
5355       if (((image->channels & CompositeMaskChannel) != 0) &&
5356           (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5357         return(MagickFalse);
5358     }
5359   if (nexus_info->authentic_pixel_cache != MagickFalse)
5360     {
5361       if (image->taint == MagickFalse)
5362         image->taint=MagickTrue;
5363       return(MagickTrue);
5364     }
5365   assert(cache_info->signature == MagickCoreSignature);
5366   status=WritePixelCachePixels(cache_info,nexus_info,exception);
5367   if ((cache_info->metacontent_extent != 0) &&
5368       (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5369     return(MagickFalse);
5370   if ((status != MagickFalse) && (image->taint == MagickFalse))
5371     image->taint=MagickTrue;
5372   return(status);
5373 }
5374 
5375 /*
5376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5377 %                                                                             %
5378 %                                                                             %
5379 %                                                                             %
5380 +   S y n c A u t h e n t i c P i x e l C a c h e                             %
5381 %                                                                             %
5382 %                                                                             %
5383 %                                                                             %
5384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5385 %
5386 %  SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5387 %  or disk cache.  The method returns MagickTrue if the pixel region is synced,
5388 %  otherwise MagickFalse.
5389 %
5390 %  The format of the SyncAuthenticPixelsCache() method is:
5391 %
5392 %      MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5393 %        ExceptionInfo *exception)
5394 %
5395 %  A description of each parameter follows:
5396 %
5397 %    o image: the image.
5398 %
5399 %    o exception: return any errors or warnings in this structure.
5400 %
5401 */
SyncAuthenticPixelsCache(Image * image,ExceptionInfo * exception)5402 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5403   ExceptionInfo *exception)
5404 {
5405   CacheInfo
5406     *magick_restrict cache_info;
5407 
5408   const int
5409     id = GetOpenMPThreadId();
5410 
5411   MagickBooleanType
5412     status;
5413 
5414   assert(image != (Image *) NULL);
5415   assert(image->signature == MagickCoreSignature);
5416   assert(image->cache != (Cache) NULL);
5417   cache_info=(CacheInfo *) image->cache;
5418   assert(cache_info->signature == MagickCoreSignature);
5419   assert(id < (int) cache_info->number_threads);
5420   status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5421     exception);
5422   return(status);
5423 }
5424 
5425 /*
5426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5427 %                                                                             %
5428 %                                                                             %
5429 %                                                                             %
5430 %   S y n c A u t h e n t i c P i x e l s                                     %
5431 %                                                                             %
5432 %                                                                             %
5433 %                                                                             %
5434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5435 %
5436 %  SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5437 %  The method returns MagickTrue if the pixel region is flushed, otherwise
5438 %  MagickFalse.
5439 %
5440 %  The format of the SyncAuthenticPixels() method is:
5441 %
5442 %      MagickBooleanType SyncAuthenticPixels(Image *image,
5443 %        ExceptionInfo *exception)
5444 %
5445 %  A description of each parameter follows:
5446 %
5447 %    o image: the image.
5448 %
5449 %    o exception: return any errors or warnings in this structure.
5450 %
5451 */
SyncAuthenticPixels(Image * image,ExceptionInfo * exception)5452 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5453   ExceptionInfo *exception)
5454 {
5455   CacheInfo
5456     *magick_restrict cache_info;
5457 
5458   const int
5459     id = GetOpenMPThreadId();
5460 
5461   MagickBooleanType
5462     status;
5463 
5464   assert(image != (Image *) NULL);
5465   assert(image->signature == MagickCoreSignature);
5466   assert(image->cache != (Cache) NULL);
5467   cache_info=(CacheInfo *) image->cache;
5468   assert(cache_info->signature == MagickCoreSignature);
5469   if (cache_info->methods.sync_authentic_pixels_handler != (SyncAuthenticPixelsHandler) NULL)
5470     {
5471       status=cache_info->methods.sync_authentic_pixels_handler(image,
5472         exception);
5473       return(status);
5474     }
5475   assert(id < (int) cache_info->number_threads);
5476   status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5477     exception);
5478   return(status);
5479 }
5480 
5481 /*
5482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5483 %                                                                             %
5484 %                                                                             %
5485 %                                                                             %
5486 +   S y n c I m a g e P i x e l C a c h e                                     %
5487 %                                                                             %
5488 %                                                                             %
5489 %                                                                             %
5490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5491 %
5492 %  SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5493 %  The method returns MagickTrue if the pixel region is flushed, otherwise
5494 %  MagickFalse.
5495 %
5496 %  The format of the SyncImagePixelCache() method is:
5497 %
5498 %      MagickBooleanType SyncImagePixelCache(Image *image,
5499 %        ExceptionInfo *exception)
5500 %
5501 %  A description of each parameter follows:
5502 %
5503 %    o image: the image.
5504 %
5505 %    o exception: return any errors or warnings in this structure.
5506 %
5507 */
SyncImagePixelCache(Image * image,ExceptionInfo * exception)5508 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5509   ExceptionInfo *exception)
5510 {
5511   CacheInfo
5512     *magick_restrict cache_info;
5513 
5514   assert(image != (Image *) NULL);
5515   assert(exception != (ExceptionInfo *) NULL);
5516   cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5517   return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5518 }
5519 
5520 /*
5521 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5522 %                                                                             %
5523 %                                                                             %
5524 %                                                                             %
5525 +   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                       %
5526 %                                                                             %
5527 %                                                                             %
5528 %                                                                             %
5529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5530 %
5531 %  WritePixelCacheMetacontent() writes the meta-content to the specified region
5532 %  of the pixel cache.
5533 %
5534 %  The format of the WritePixelCacheMetacontent() method is:
5535 %
5536 %      MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5537 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5538 %
5539 %  A description of each parameter follows:
5540 %
5541 %    o cache_info: the pixel cache.
5542 %
5543 %    o nexus_info: the cache nexus to write the meta-content.
5544 %
5545 %    o exception: return any errors or warnings in this structure.
5546 %
5547 */
WritePixelCacheMetacontent(CacheInfo * cache_info,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)5548 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5549   NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5550 {
5551   MagickOffsetType
5552     count,
5553     offset;
5554 
5555   MagickSizeType
5556     extent,
5557     length;
5558 
5559   const unsigned char
5560     *magick_restrict p;
5561 
5562   ssize_t
5563     y;
5564 
5565   size_t
5566     rows;
5567 
5568   if (cache_info->metacontent_extent == 0)
5569     return(MagickFalse);
5570   if (nexus_info->authentic_pixel_cache != MagickFalse)
5571     return(MagickTrue);
5572   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5573     nexus_info->region.x;
5574   length=(MagickSizeType) nexus_info->region.width*
5575     cache_info->metacontent_extent;
5576   extent=(MagickSizeType) length*nexus_info->region.height;
5577   rows=nexus_info->region.height;
5578   y=0;
5579   p=(unsigned char *) nexus_info->metacontent;
5580   switch (cache_info->type)
5581   {
5582     case MemoryCache:
5583     case MapCache:
5584     {
5585       unsigned char
5586         *magick_restrict q;
5587 
5588       /*
5589         Write associated pixels to memory.
5590       */
5591       if ((cache_info->columns == nexus_info->region.width) &&
5592           (extent == (MagickSizeType) ((size_t) extent)))
5593         {
5594           length=extent;
5595           rows=1UL;
5596         }
5597       q=(unsigned char *) cache_info->metacontent+offset*
5598         cache_info->metacontent_extent;
5599       for (y=0; y < (ssize_t) rows; y++)
5600       {
5601         (void) memcpy(q,p,(size_t) length);
5602         p+=nexus_info->region.width*cache_info->metacontent_extent;
5603         q+=cache_info->columns*cache_info->metacontent_extent;
5604       }
5605       break;
5606     }
5607     case DiskCache:
5608     {
5609       /*
5610         Write associated pixels to disk.
5611       */
5612       LockSemaphoreInfo(cache_info->file_semaphore);
5613       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5614         {
5615           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5616             cache_info->cache_filename);
5617           UnlockSemaphoreInfo(cache_info->file_semaphore);
5618           return(MagickFalse);
5619         }
5620       if ((cache_info->columns == nexus_info->region.width) &&
5621           (extent <= MagickMaxBufferExtent))
5622         {
5623           length=extent;
5624           rows=1UL;
5625         }
5626       extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5627       for (y=0; y < (ssize_t) rows; y++)
5628       {
5629         count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5630           cache_info->number_channels*sizeof(Quantum)+offset*
5631           cache_info->metacontent_extent,length,(const unsigned char *) p);
5632         if (count != (MagickOffsetType) length)
5633           break;
5634         p+=cache_info->metacontent_extent*nexus_info->region.width;
5635         offset+=cache_info->columns;
5636       }
5637       if (IsFileDescriptorLimitExceeded() != MagickFalse)
5638         (void) ClosePixelCacheOnDisk(cache_info);
5639       UnlockSemaphoreInfo(cache_info->file_semaphore);
5640       break;
5641     }
5642     case DistributedCache:
5643     {
5644       RectangleInfo
5645         region;
5646 
5647       /*
5648         Write metacontent to distributed cache.
5649       */
5650       LockSemaphoreInfo(cache_info->file_semaphore);
5651       region=nexus_info->region;
5652       if ((cache_info->columns != nexus_info->region.width) ||
5653           (extent > MagickMaxBufferExtent))
5654         region.height=1UL;
5655       else
5656         {
5657           length=extent;
5658           rows=1UL;
5659         }
5660       for (y=0; y < (ssize_t) rows; y++)
5661       {
5662         count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5663           cache_info->server_info,&region,length,(const unsigned char *) p);
5664         if (count != (MagickOffsetType) length)
5665           break;
5666         p+=cache_info->metacontent_extent*nexus_info->region.width;
5667         region.y++;
5668       }
5669       UnlockSemaphoreInfo(cache_info->file_semaphore);
5670       break;
5671     }
5672     default:
5673       break;
5674   }
5675   if (y < (ssize_t) rows)
5676     {
5677       ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5678         cache_info->cache_filename);
5679       return(MagickFalse);
5680     }
5681   if ((cache_info->debug != MagickFalse) &&
5682       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5683     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5684       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5685       nexus_info->region.width,(double) nexus_info->region.height,(double)
5686       nexus_info->region.x,(double) nexus_info->region.y);
5687   return(MagickTrue);
5688 }
5689 
5690 /*
5691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5692 %                                                                             %
5693 %                                                                             %
5694 %                                                                             %
5695 +   W r i t e C a c h e P i x e l s                                           %
5696 %                                                                             %
5697 %                                                                             %
5698 %                                                                             %
5699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5700 %
5701 %  WritePixelCachePixels() writes image pixels to the specified region of the
5702 %  pixel cache.
5703 %
5704 %  The format of the WritePixelCachePixels() method is:
5705 %
5706 %      MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5707 %        NexusInfo *nexus_info,ExceptionInfo *exception)
5708 %
5709 %  A description of each parameter follows:
5710 %
5711 %    o cache_info: the pixel cache.
5712 %
5713 %    o nexus_info: the cache nexus to write the pixels.
5714 %
5715 %    o exception: return any errors or warnings in this structure.
5716 %
5717 */
WritePixelCachePixels(CacheInfo * magick_restrict cache_info,NexusInfo * magick_restrict nexus_info,ExceptionInfo * exception)5718 static MagickBooleanType WritePixelCachePixels(
5719   CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5720   ExceptionInfo *exception)
5721 {
5722   MagickOffsetType
5723     count,
5724     offset;
5725 
5726   MagickSizeType
5727     extent,
5728     length;
5729 
5730   const Quantum
5731     *magick_restrict p;
5732 
5733   ssize_t
5734     y;
5735 
5736   size_t
5737     rows;
5738 
5739   if (nexus_info->authentic_pixel_cache != MagickFalse)
5740     return(MagickTrue);
5741   offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5742     nexus_info->region.x;
5743   length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5744     sizeof(Quantum);
5745   extent=length*nexus_info->region.height;
5746   rows=nexus_info->region.height;
5747   y=0;
5748   p=nexus_info->pixels;
5749   switch (cache_info->type)
5750   {
5751     case MemoryCache:
5752     case MapCache:
5753     {
5754       Quantum
5755         *magick_restrict q;
5756 
5757       /*
5758         Write pixels to memory.
5759       */
5760       if ((cache_info->columns == nexus_info->region.width) &&
5761           (extent == (MagickSizeType) ((size_t) extent)))
5762         {
5763           length=extent;
5764           rows=1UL;
5765         }
5766       q=cache_info->pixels+cache_info->number_channels*offset;
5767       for (y=0; y < (ssize_t) rows; y++)
5768       {
5769         (void) memcpy(q,p,(size_t) length);
5770         p+=cache_info->number_channels*nexus_info->region.width;
5771         q+=cache_info->number_channels*cache_info->columns;
5772       }
5773       break;
5774     }
5775     case DiskCache:
5776     {
5777       /*
5778         Write pixels to disk.
5779       */
5780       LockSemaphoreInfo(cache_info->file_semaphore);
5781       if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5782         {
5783           ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5784             cache_info->cache_filename);
5785           UnlockSemaphoreInfo(cache_info->file_semaphore);
5786           return(MagickFalse);
5787         }
5788       if ((cache_info->columns == nexus_info->region.width) &&
5789           (extent <= MagickMaxBufferExtent))
5790         {
5791           length=extent;
5792           rows=1UL;
5793         }
5794       for (y=0; y < (ssize_t) rows; y++)
5795       {
5796         count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5797           cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5798           p);
5799         if (count != (MagickOffsetType) length)
5800           break;
5801         p+=cache_info->number_channels*nexus_info->region.width;
5802         offset+=cache_info->columns;
5803       }
5804       if (IsFileDescriptorLimitExceeded() != MagickFalse)
5805         (void) ClosePixelCacheOnDisk(cache_info);
5806       UnlockSemaphoreInfo(cache_info->file_semaphore);
5807       break;
5808     }
5809     case DistributedCache:
5810     {
5811       RectangleInfo
5812         region;
5813 
5814       /*
5815         Write pixels to distributed cache.
5816       */
5817       LockSemaphoreInfo(cache_info->file_semaphore);
5818       region=nexus_info->region;
5819       if ((cache_info->columns != nexus_info->region.width) ||
5820           (extent > MagickMaxBufferExtent))
5821         region.height=1UL;
5822       else
5823         {
5824           length=extent;
5825           rows=1UL;
5826         }
5827       for (y=0; y < (ssize_t) rows; y++)
5828       {
5829         count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5830           cache_info->server_info,&region,length,(const unsigned char *) p);
5831         if (count != (MagickOffsetType) length)
5832           break;
5833         p+=cache_info->number_channels*nexus_info->region.width;
5834         region.y++;
5835       }
5836       UnlockSemaphoreInfo(cache_info->file_semaphore);
5837       break;
5838     }
5839     default:
5840       break;
5841   }
5842   if (y < (ssize_t) rows)
5843     {
5844       ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5845         cache_info->cache_filename);
5846       return(MagickFalse);
5847     }
5848   if ((cache_info->debug != MagickFalse) &&
5849       (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5850     (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5851       "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5852       nexus_info->region.width,(double) nexus_info->region.height,(double)
5853       nexus_info->region.x,(double) nexus_info->region.y);
5854   return(MagickTrue);
5855 }
5856