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