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