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