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