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