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