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