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