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