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