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