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