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