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