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