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