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