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