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