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