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 *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  assert(exception != (ExceptionInfo *) NULL);
2332  assert(exception->signature == MagickCoreSignature);
2333  cache_info=(CacheInfo *) image->cache;
2334  assert(cache_info->signature == MagickCoreSignature);
2335  *length=cache_info->length;
2336  if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2337  return((void *) NULL);
2338  return((void *) cache_info->pixels);
2339 }
2340 
2341 /*
2342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2343 % %
2344 % %
2345 % %
2346 + 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 %
2347 % %
2348 % %
2349 % %
2350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2351 %
2352 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2353 %
2354 % The format of the GetPixelCacheStorageClass() method is:
2355 %
2356 % ClassType GetPixelCacheStorageClass(Cache cache)
2357 %
2358 % A description of each parameter follows:
2359 %
2360 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2361 %
2362 % o cache: the pixel cache.
2363 %
2364 */
2366 {
2367  CacheInfo
2368  *magick_restrict cache_info;
2369 
2370  assert(cache != (Cache) NULL);
2371  cache_info=(CacheInfo *) cache;
2372  assert(cache_info->signature == MagickCoreSignature);
2373  if (cache_info->debug != MagickFalse)
2375  cache_info->filename);
2376  return(cache_info->storage_class);
2377 }
2378 
2379 /*
2380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2381 % %
2382 % %
2383 % %
2384 + G e t P i x e l C a c h e T i l e S i z e %
2385 % %
2386 % %
2387 % %
2388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2389 %
2390 % GetPixelCacheTileSize() returns the pixel cache tile size.
2391 %
2392 % The format of the GetPixelCacheTileSize() method is:
2393 %
2394 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2395 % size_t *height)
2396 %
2397 % A description of each parameter follows:
2398 %
2399 % o image: the image.
2400 %
2401 % o width: the optimized cache tile width in pixels.
2402 %
2403 % o height: the optimized cache tile height in pixels.
2404 %
2405 */
2406 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2407  size_t *height)
2408 {
2409  CacheInfo
2410  *magick_restrict cache_info;
2411 
2412  assert(image != (Image *) NULL);
2413  assert(image->signature == MagickCoreSignature);
2414  if (image->debug != MagickFalse)
2415  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2416  cache_info=(CacheInfo *) image->cache;
2417  assert(cache_info->signature == MagickCoreSignature);
2418  *width=2048UL/(MagickMax(cache_info->number_channels,1)*sizeof(Quantum));
2419  if (GetImagePixelCacheType(image) == DiskCache)
2420  *width=8192UL/(MagickMax(cache_info->number_channels,1)*sizeof(Quantum));
2421  *height=(*width);
2422 }
2423 
2424 /*
2425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2426 % %
2427 % %
2428 % %
2429 + 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 %
2430 % %
2431 % %
2432 % %
2433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2434 %
2435 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2436 % pixel cache. A virtual pixel is any pixel access that is outside the
2437 % boundaries of the image cache.
2438 %
2439 % The format of the GetPixelCacheVirtualMethod() method is:
2440 %
2441 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2442 %
2443 % A description of each parameter follows:
2444 %
2445 % o image: the image.
2446 %
2447 */
2449 {
2450  CacheInfo
2451  *magick_restrict cache_info;
2452 
2453  assert(image != (Image *) NULL);
2454  assert(image->signature == MagickCoreSignature);
2455  assert(image->cache != (Cache) NULL);
2456  cache_info=(CacheInfo *) image->cache;
2457  assert(cache_info->signature == MagickCoreSignature);
2458  return(cache_info->virtual_pixel_method);
2459 }
2460 
2461 /*
2462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2463 % %
2464 % %
2465 % %
2466 + 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 %
2467 % %
2468 % %
2469 % %
2470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2471 %
2472 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2473 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2474 %
2475 % The format of the GetVirtualMetacontentFromCache() method is:
2476 %
2477 % void *GetVirtualMetacontentFromCache(const Image *image)
2478 %
2479 % A description of each parameter follows:
2480 %
2481 % o image: the image.
2482 %
2483 */
2484 static const void *GetVirtualMetacontentFromCache(const Image *image)
2485 {
2486  CacheInfo
2487  *magick_restrict cache_info;
2488 
2489  const int
2490  id = GetOpenMPThreadId();
2491 
2492  const void
2493  *magick_restrict metacontent;
2494 
2495  assert(image != (const Image *) NULL);
2496  assert(image->signature == MagickCoreSignature);
2497  assert(image->cache != (Cache) NULL);
2498  cache_info=(CacheInfo *) image->cache;
2499  assert(cache_info->signature == MagickCoreSignature);
2500  assert(id < (int) cache_info->number_threads);
2501  metacontent=GetVirtualMetacontentFromNexus(cache_info,
2502  cache_info->nexus_info[id]);
2503  return(metacontent);
2504 }
2505 
2506 /*
2507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2508 % %
2509 % %
2510 % %
2511 + 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 %
2512 % %
2513 % %
2514 % %
2515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2516 %
2517 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2518 % cache nexus.
2519 %
2520 % The format of the GetVirtualMetacontentFromNexus() method is:
2521 %
2522 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2523 % NexusInfo *nexus_info)
2524 %
2525 % A description of each parameter follows:
2526 %
2527 % o cache: the pixel cache.
2528 %
2529 % o nexus_info: the cache nexus to return the meta-content.
2530 %
2531 */
2533  NexusInfo *magick_restrict nexus_info)
2534 {
2535  CacheInfo
2536  *magick_restrict cache_info;
2537 
2538  assert(cache != (Cache) NULL);
2539  cache_info=(CacheInfo *) cache;
2540  assert(cache_info->signature == MagickCoreSignature);
2541  if (cache_info->storage_class == UndefinedClass)
2542  return((void *) NULL);
2543  return(nexus_info->metacontent);
2544 }
2545 
2546 /*
2547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2548 % %
2549 % %
2550 % %
2551 % G e t V i r t u a l M e t a c o n t e n t %
2552 % %
2553 % %
2554 % %
2555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2556 %
2557 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2558 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2559 % returned if the meta-content are not available.
2560 %
2561 % The format of the GetVirtualMetacontent() method is:
2562 %
2563 % const void *GetVirtualMetacontent(const Image *image)
2564 %
2565 % A description of each parameter follows:
2566 %
2567 % o image: the image.
2568 %
2569 */
2570 MagickExport const void *GetVirtualMetacontent(const Image *image)
2571 {
2572  CacheInfo
2573  *magick_restrict cache_info;
2574 
2575  const int
2576  id = GetOpenMPThreadId();
2577 
2578  const void
2579  *magick_restrict metacontent;
2580 
2581  assert(image != (const Image *) NULL);
2582  assert(image->signature == MagickCoreSignature);
2583  assert(image->cache != (Cache) NULL);
2584  cache_info=(CacheInfo *) image->cache;
2585  assert(cache_info->signature == MagickCoreSignature);
2586  metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2587  if (metacontent != (void *) NULL)
2588  return(metacontent);
2589  assert(id < (int) cache_info->number_threads);
2590  metacontent=GetVirtualMetacontentFromNexus(cache_info,
2591  cache_info->nexus_info[id]);
2592  return(metacontent);
2593 }
2594 
2595 /*
2596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2597 % %
2598 % %
2599 % %
2600 + 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 %
2601 % %
2602 % %
2603 % %
2604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2605 %
2606 % GetVirtualPixelCacheNexus() gets virtual pixels from the in-memory or disk
2607 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2608 % is returned if the pixels are transferred, otherwise a NULL is returned.
2609 %
2610 % The format of the GetVirtualPixelCacheNexus() method is:
2611 %
2612 % Quantum *GetVirtualPixelCacheNexus(const Image *image,
2613 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2614 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2615 % ExceptionInfo *exception)
2616 %
2617 % A description of each parameter follows:
2618 %
2619 % o image: the image.
2620 %
2621 % o virtual_pixel_method: the virtual pixel method.
2622 %
2623 % o x,y,columns,rows: These values define the perimeter of a region of
2624 % pixels.
2625 %
2626 % o nexus_info: the cache nexus to acquire.
2627 %
2628 % o exception: return any errors or warnings in this structure.
2629 %
2630 */
2631 
2632 static ssize_t
2634  {
2635  0, 48, 12, 60, 3, 51, 15, 63,
2636  32, 16, 44, 28, 35, 19, 47, 31,
2637  8, 56, 4, 52, 11, 59, 7, 55,
2638  40, 24, 36, 20, 43, 27, 39, 23,
2639  2, 50, 14, 62, 1, 49, 13, 61,
2640  34, 18, 46, 30, 33, 17, 45, 29,
2641  10, 58, 6, 54, 9, 57, 5, 53,
2642  42, 26, 38, 22, 41, 25, 37, 21
2643  };
2644 
2645 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2646 {
2647  ssize_t
2648  index;
2649 
2650  index=x+DitherMatrix[x & 0x07]-32L;
2651  if (index < 0L)
2652  return(0L);
2653  if (index >= (ssize_t) columns)
2654  return((ssize_t) columns-1L);
2655  return(index);
2656 }
2657 
2658 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2659 {
2660  ssize_t
2661  index;
2662 
2663  index=y+DitherMatrix[y & 0x07]-32L;
2664  if (index < 0L)
2665  return(0L);
2666  if (index >= (ssize_t) rows)
2667  return((ssize_t) rows-1L);
2668  return(index);
2669 }
2670 
2671 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2672 {
2673  if (x < 0L)
2674  return(0L);
2675  if (x >= (ssize_t) columns)
2676  return((ssize_t) (columns-1));
2677  return(x);
2678 }
2679 
2680 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2681 {
2682  if (y < 0L)
2683  return(0L);
2684  if (y >= (ssize_t) rows)
2685  return((ssize_t) (rows-1));
2686  return(y);
2687 }
2688 
2689 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2690 {
2691  return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2692 }
2693 
2694 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2695 {
2696  return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2697 }
2698 
2699 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2700  const size_t extent)
2701 {
2702  MagickModulo
2703  modulo;
2704 
2705  modulo.quotient=offset;
2706  if (extent != 0)
2707  modulo.quotient=offset/((ssize_t) extent);
2708  modulo.remainder=offset % ((ssize_t) extent);
2709  if ((modulo.remainder != 0) && ((offset ^ ((ssize_t) extent)) < 0))
2710  {
2711  modulo.quotient-=1;
2712  modulo.remainder+=((ssize_t) extent);
2713  }
2714  return(modulo);
2715 }
2716 
2718  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2719  const size_t columns,const size_t rows,NexusInfo *nexus_info,
2720  ExceptionInfo *exception)
2721 {
2722  CacheInfo
2723  *magick_restrict cache_info;
2724 
2726  offset;
2727 
2729  length,
2730  number_pixels;
2731 
2732  NexusInfo
2733  *magick_restrict virtual_nexus;
2734 
2735  Quantum
2736  *magick_restrict pixels,
2737  virtual_pixel[MaxPixelChannels];
2738 
2739  const Quantum
2740  *magick_restrict p;
2741 
2742  const void
2743  *magick_restrict r;
2744 
2745  Quantum
2746  *magick_restrict q;
2747 
2748  ssize_t
2749  i,
2750  u;
2751 
2752  unsigned char
2753  *magick_restrict s;
2754 
2755  ssize_t
2756  v;
2757 
2758  void
2759  *magick_restrict virtual_metacontent;
2760 
2761  /*
2762  Acquire pixels.
2763  */
2764  assert(image != (const Image *) NULL);
2765  assert(image->signature == MagickCoreSignature);
2766  assert(image->cache != (Cache) NULL);
2767  cache_info=(CacheInfo *) image->cache;
2768  assert(cache_info->signature == MagickCoreSignature);
2769  if (cache_info->type == UndefinedCache)
2770  return((const Quantum *) NULL);
2771 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2772  CopyOpenCLBuffer(cache_info);
2773 #endif
2774  pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,x,y,columns,rows,
2775  ((image->channels & WriteMaskChannel) != 0) ||
2776  ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
2777  nexus_info,exception);
2778  if (pixels == (Quantum *) NULL)
2779  return((const Quantum *) NULL);
2780  q=pixels;
2781  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2782  nexus_info->region.x;
2783  length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2784  nexus_info->region.width-1L;
2785  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2786  if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2787  if ((x >= 0) && ((ssize_t) (x+columns-1) < (ssize_t) cache_info->columns) &&
2788  (y >= 0) && ((ssize_t) (y+rows-1) < (ssize_t) cache_info->rows))
2789  {
2791  status;
2792 
2793  /*
2794  Pixel request is inside cache extents.
2795  */
2796  if (nexus_info->authentic_pixel_cache != MagickFalse)
2797  return(q);
2798  status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2799  if (status == MagickFalse)
2800  return((const Quantum *) NULL);
2801  if (cache_info->metacontent_extent != 0)
2802  {
2803  status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2804  if (status == MagickFalse)
2805  return((const Quantum *) NULL);
2806  }
2807  return(q);
2808  }
2809  /*
2810  Pixel request is outside cache extents.
2811  */
2812  virtual_nexus=nexus_info->virtual_nexus;
2813  s=(unsigned char *) nexus_info->metacontent;
2814  (void) memset(virtual_pixel,0,cache_info->number_channels*
2815  sizeof(*virtual_pixel));
2816  virtual_metacontent=(void *) NULL;
2817  switch (virtual_pixel_method)
2818  {
2829  {
2830  if (cache_info->metacontent_extent != 0)
2831  {
2832  /*
2833  Acquire a metacontent buffer.
2834  */
2835  virtual_metacontent=(void *) AcquireQuantumMemory(1,
2836  cache_info->metacontent_extent);
2837  if (virtual_metacontent == (void *) NULL)
2838  {
2839  (void) ThrowMagickException(exception,GetMagickModule(),
2840  CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2841  return((const Quantum *) NULL);
2842  }
2843  (void) memset(virtual_metacontent,0,cache_info->metacontent_extent);
2844  }
2845  switch (virtual_pixel_method)
2846  {
2848  {
2849  for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2850  SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2851  SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2852  break;
2853  }
2855  {
2856  for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2858  virtual_pixel);
2859  SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2860  break;
2861  }
2863  {
2864  for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2865  SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2866  SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2867  break;
2868  }
2871  {
2872  for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2873  SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2874  SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2875  break;
2876  }
2877  default:
2878  {
2880  virtual_pixel);
2882  virtual_pixel);
2884  virtual_pixel);
2886  virtual_pixel);
2888  virtual_pixel);
2889  break;
2890  }
2891  }
2892  break;
2893  }
2894  default:
2895  break;
2896  }
2897  for (v=0; v < (ssize_t) rows; v++)
2898  {
2899  ssize_t
2900  y_offset;
2901 
2902  y_offset=y+v;
2903  if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2904  (virtual_pixel_method == UndefinedVirtualPixelMethod))
2905  y_offset=EdgeY(y_offset,cache_info->rows);
2906  for (u=0; u < (ssize_t) columns; u+=length)
2907  {
2908  ssize_t
2909  x_offset;
2910 
2911  x_offset=x+u;
2912  length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2913  if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2914  ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2915  (length == 0))
2916  {
2917  MagickModulo
2918  x_modulo,
2919  y_modulo;
2920 
2921  /*
2922  Transfer a single pixel.
2923  */
2924  length=(MagickSizeType) 1;
2925  switch (virtual_pixel_method)
2926  {
2928  default:
2929  {
2930  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2931  EdgeX(x_offset,cache_info->columns),
2932  EdgeY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
2933  exception);
2934  r=GetVirtualMetacontentFromNexus(cache_info,
2935  nexus_info->virtual_nexus);
2936  break;
2937  }
2939  {
2940  if (cache_info->random_info == (RandomInfo *) NULL)
2941  cache_info->random_info=AcquireRandomInfo();
2942  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2943  RandomX(cache_info->random_info,cache_info->columns),
2944  RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2945  virtual_nexus,exception);
2946  r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2947  break;
2948  }
2950  {
2951  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2952  DitherX(x_offset,cache_info->columns),
2953  DitherY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
2954  exception);
2955  r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2956  break;
2957  }
2959  {
2960  x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2961  y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2962  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2963  x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
2964  exception);
2965  r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2966  break;
2967  }
2969  {
2970  x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2971  if ((x_modulo.quotient & 0x01) == 1L)
2972  x_modulo.remainder=(ssize_t) cache_info->columns-
2973  x_modulo.remainder-1L;
2974  y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2975  if ((y_modulo.quotient & 0x01) == 1L)
2976  y_modulo.remainder=(ssize_t) cache_info->rows-
2977  y_modulo.remainder-1L;
2978  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2979  x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
2980  exception);
2981  r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2982  break;
2983  }
2985  {
2986  x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2987  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2988  x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2989  virtual_nexus,exception);
2990  r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
2991  break;
2992  }
2994  {
2995  y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2996  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
2997  EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2998  virtual_nexus,exception);
2999  r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3000  break;
3001  }
3008  {
3009  p=virtual_pixel;
3010  r=virtual_metacontent;
3011  break;
3012  }
3014  {
3015  x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3016  y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3017  if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3018  {
3019  p=virtual_pixel;
3020  r=virtual_metacontent;
3021  break;
3022  }
3023  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3024  x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3025  exception);
3026  r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3027  break;
3028  }
3030  {
3031  if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
3032  {
3033  p=virtual_pixel;
3034  r=virtual_metacontent;
3035  break;
3036  }
3037  x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3038  y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3039  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3040  x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3041  exception);
3042  r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3043  break;
3044  }
3046  {
3047  if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
3048  {
3049  p=virtual_pixel;
3050  r=virtual_metacontent;
3051  break;
3052  }
3053  x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3054  y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3055  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3056  x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3057  exception);
3058  r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3059  break;
3060  }
3061  }
3062  if (p == (const Quantum *) NULL)
3063  break;
3064  (void) memcpy(q,p,(size_t) (cache_info->number_channels*length*
3065  sizeof(*p)));
3066  q+=cache_info->number_channels;
3067  if ((s != (void *) NULL) && (r != (const void *) NULL))
3068  {
3069  (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3070  s+=cache_info->metacontent_extent;
3071  }
3072  continue;
3073  }
3074  /*
3075  Transfer a run of pixels.
3076  */
3077  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x_offset,y_offset,
3078  (size_t) length,1UL,virtual_nexus,exception);
3079  if (p == (const Quantum *) NULL)
3080  break;
3081  r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3082  (void) memcpy(q,p,(size_t) (cache_info->number_channels*length*
3083  sizeof(*p)));
3084  q+=cache_info->number_channels*length;
3085  if ((r != (void *) NULL) && (s != (const void *) NULL))
3086  {
3087  (void) memcpy(s,r,(size_t) length);
3088  s+=length*cache_info->metacontent_extent;
3089  }
3090  }
3091  if (u < (ssize_t) columns)
3092  break;
3093  }
3094  /*
3095  Free resources.
3096  */
3097  if (virtual_metacontent != (void *) NULL)
3098  virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3099  if (v < (ssize_t) rows)
3100  return((const Quantum *) NULL);
3101  return(pixels);
3102 }
3103 
3104 /*
3105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3106 % %
3107 % %
3108 % %
3109 + G e t V i r t u a l P i x e l C a c h e %
3110 % %
3111 % %
3112 % %
3113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3114 %
3115 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3116 % cache as defined by the geometry parameters. A pointer to the pixels
3117 % is returned if the pixels are transferred, otherwise a NULL is returned.
3118 %
3119 % The format of the GetVirtualPixelCache() method is:
3120 %
3121 % const Quantum *GetVirtualPixelCache(const Image *image,
3122 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3123 % const ssize_t y,const size_t columns,const size_t rows,
3124 % ExceptionInfo *exception)
3125 %
3126 % A description of each parameter follows:
3127 %
3128 % o image: the image.
3129 %
3130 % o virtual_pixel_method: the virtual pixel method.
3131 %
3132 % o x,y,columns,rows: These values define the perimeter of a region of
3133 % pixels.
3134 %
3135 % o exception: return any errors or warnings in this structure.
3136 %
3137 */
3138 static const Quantum *GetVirtualPixelCache(const Image *image,
3139  const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3140  const size_t columns,const size_t rows,ExceptionInfo *exception)
3141 {
3142  CacheInfo
3143  *magick_restrict cache_info;
3144 
3145  const int
3146  id = GetOpenMPThreadId();
3147 
3148  const Quantum
3149  *magick_restrict p;
3150 
3151  assert(image != (const Image *) NULL);
3152  assert(image->signature == MagickCoreSignature);
3153  assert(image->cache != (Cache) NULL);
3154  cache_info=(CacheInfo *) image->cache;
3155  assert(cache_info->signature == MagickCoreSignature);
3156  assert(id < (int) cache_info->number_threads);
3157  p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,columns,rows,
3158  cache_info->nexus_info[id],exception);
3159  return(p);
3160 }
3161 
3162 /*
3163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3164 % %
3165 % %
3166 % %
3167 % G e t V i r t u a l P i x e l Q u e u e %
3168 % %
3169 % %
3170 % %
3171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3172 %
3173 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3174 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3175 %
3176 % The format of the GetVirtualPixelQueue() method is:
3177 %
3178 % const Quantum *GetVirtualPixelQueue(const Image image)
3179 %
3180 % A description of each parameter follows:
3181 %
3182 % o image: the image.
3183 %
3184 */
3186 {
3187  CacheInfo
3188  *magick_restrict cache_info;
3189 
3190  const int
3191  id = GetOpenMPThreadId();
3192 
3193  assert(image != (const Image *) NULL);
3194  assert(image->signature == MagickCoreSignature);
3195  assert(image->cache != (Cache) NULL);
3196  cache_info=(CacheInfo *) image->cache;
3197  assert(cache_info->signature == MagickCoreSignature);
3198  if (cache_info->methods.get_virtual_pixels_handler !=
3199  (GetVirtualPixelsHandler) NULL)
3200  return(cache_info->methods.get_virtual_pixels_handler(image));
3201  assert(id < (int) cache_info->number_threads);
3202  return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3203 }
3204 
3205 /*
3206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3207 % %
3208 % %
3209 % %
3210 % G e t V i r t u a l P i x e l s %
3211 % %
3212 % %
3213 % %
3214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3215 %
3216 % GetVirtualPixels() returns an immutable pixel region. If the
3217 % region is successfully accessed, a pointer to it is returned, otherwise
3218 % NULL is returned. The returned pointer may point to a temporary working
3219 % copy of the pixels or it may point to the original pixels in memory.
3220 % Performance is maximized if the selected region is part of one row, or one
3221 % or more full rows, since there is opportunity to access the pixels in-place
3222 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3223 % returned pointer must *never* be deallocated by the user.
3224 %
3225 % Pixels accessed via the returned pointer represent a simple array of type
3226 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3227 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3228 % access the meta-content (of type void) corresponding to the
3229 % region.
3230 %
3231 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3232 %
3233 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3234 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3235 % GetCacheViewAuthenticPixels() instead.
3236 %
3237 % The format of the GetVirtualPixels() method is:
3238 %
3239 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3240 % const ssize_t y,const size_t columns,const size_t rows,
3241 % ExceptionInfo *exception)
3242 %
3243 % A description of each parameter follows:
3244 %
3245 % o image: the image.
3246 %
3247 % o x,y,columns,rows: These values define the perimeter of a region of
3248 % pixels.
3249 %
3250 % o exception: return any errors or warnings in this structure.
3251 %
3252 */
3254  const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3255  ExceptionInfo *exception)
3256 {
3257  CacheInfo
3258  *magick_restrict cache_info;
3259 
3260  const int
3261  id = GetOpenMPThreadId();
3262 
3263  const Quantum
3264  *magick_restrict p;
3265 
3266  assert(image != (const Image *) NULL);
3267  assert(image->signature == MagickCoreSignature);
3268  assert(image->cache != (Cache) NULL);
3269  cache_info=(CacheInfo *) image->cache;
3270  assert(cache_info->signature == MagickCoreSignature);
3271  if (cache_info->methods.get_virtual_pixel_handler !=
3272  (GetVirtualPixelHandler) NULL)
3273  return(cache_info->methods.get_virtual_pixel_handler(image,
3274  GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3275  assert(id < (int) cache_info->number_threads);
3277  columns,rows,cache_info->nexus_info[id],exception);
3278  return(p);
3279 }
3280 
3281 /*
3282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3283 % %
3284 % %
3285 % %
3286 + 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 %
3287 % %
3288 % %
3289 % %
3290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3291 %
3292 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3293 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3294 %
3295 % The format of the GetVirtualPixelsCache() method is:
3296 %
3297 % Quantum *GetVirtualPixelsCache(const Image *image)
3298 %
3299 % A description of each parameter follows:
3300 %
3301 % o image: the image.
3302 %
3303 */
3304 static const Quantum *GetVirtualPixelsCache(const Image *image)
3305 {
3306  CacheInfo
3307  *magick_restrict cache_info;
3308 
3309  const int
3310  id = GetOpenMPThreadId();
3311 
3312  assert(image != (const Image *) NULL);
3313  assert(image->signature == MagickCoreSignature);
3314  assert(image->cache != (Cache) NULL);
3315  cache_info=(CacheInfo *) image->cache;
3316  assert(cache_info->signature == MagickCoreSignature);
3317  assert(id < (int) cache_info->number_threads);
3318  return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3319 }
3320 
3321 /*
3322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3323 % %
3324 % %
3325 % %
3326 + G e t V i r t u a l P i x e l s N e x u s %
3327 % %
3328 % %
3329 % %
3330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3331 %
3332 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3333 % cache nexus.
3334 %
3335 % The format of the GetVirtualPixelsNexus() method is:
3336 %
3337 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3338 % NexusInfo *nexus_info)
3339 %
3340 % A description of each parameter follows:
3341 %
3342 % o cache: the pixel cache.
3343 %
3344 % o nexus_info: the cache nexus to return the colormap pixels.
3345 %
3346 */
3348  NexusInfo *magick_restrict nexus_info)
3349 {
3350  CacheInfo
3351  *magick_restrict cache_info;
3352 
3353  assert(cache != (Cache) NULL);
3354  cache_info=(CacheInfo *) cache;
3355  assert(cache_info->signature == MagickCoreSignature);
3356  if (cache_info->storage_class == UndefinedClass)
3357  return((Quantum *) NULL);
3358  return((const Quantum *) nexus_info->pixels);
3359 }
3360 
3361 /*
3362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3363 % %
3364 % %
3365 % %
3366 + M a s k P i x e l C a c h e N e x u s %
3367 % %
3368 % %
3369 % %
3370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3371 %
3372 % MaskPixelCacheNexus() masks the cache nexus as defined by the composite mask.
3373 % The method returns MagickTrue if the pixel region is masked, otherwise
3374 % MagickFalse.
3375 %
3376 % The format of the MaskPixelCacheNexus() method is:
3377 %
3378 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3379 % NexusInfo *nexus_info,ExceptionInfo *exception)
3380 %
3381 % A description of each parameter follows:
3382 %
3383 % o image: the image.
3384 %
3385 % o nexus_info: the cache nexus to clip.
3386 %
3387 % o exception: return any errors or warnings in this structure.
3388 %
3389 */
3390 
3392  const MagickRealType alpha,const Quantum q,const MagickRealType beta)
3393 {
3394  double
3395  gamma;
3396 
3397  if (fabs((double) (alpha-TransparentAlpha)) < MagickEpsilon)
3398  return(q);
3399  gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3400  gamma=PerceptibleReciprocal(gamma);
3401  return(ClampToQuantum(gamma*MagickOver_((double) p,alpha,(double) q,beta)));
3402 }
3403 
3405  ExceptionInfo *exception)
3406 {
3407  CacheInfo
3408  *magick_restrict cache_info;
3409 
3410  Quantum
3411  *magick_restrict p,
3412  *magick_restrict q;
3413 
3414  ssize_t
3415  y;
3416 
3417  /*
3418  Apply composite mask.
3419  */
3420  if (image->debug != MagickFalse)
3421  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3422  if ((image->channels & CompositeMaskChannel) == 0)
3423  return(MagickTrue);
3424  if ((nexus_info->region.width == 0) || (nexus_info->region.height == 0))
3425  return(MagickTrue);
3426  cache_info=(CacheInfo *) image->cache;
3427  if (cache_info == (Cache) NULL)
3428  return(MagickFalse);
3429  p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3430  nexus_info->region.width,nexus_info->region.height,
3431  nexus_info->virtual_nexus,exception);
3432  q=nexus_info->pixels;
3433  if ((p == (Quantum *) NULL) || (q == (Quantum *) NULL))
3434  return(MagickFalse);
3435  for (y=0; y < (ssize_t) nexus_info->region.height; y++)
3436  {
3437  ssize_t
3438  x;
3439 
3440  for (x=0; x < (ssize_t) nexus_info->region.width; x++)
3441  {
3442  double
3443  alpha;
3444 
3445  ssize_t
3446  i;
3447 
3448  alpha=(double) GetPixelCompositeMask(image,p);
3449  for (i=0; i < (ssize_t) image->number_channels; i++)
3450  {
3451  PixelChannel channel = GetPixelChannelChannel(image,i);
3452  PixelTrait traits = GetPixelChannelTraits(image,channel);
3453  if ((traits & UpdatePixelTrait) == 0)
3454  continue;
3455  q[i]=ApplyPixelCompositeMask(q[i],alpha,p[i],GetPixelAlpha(image,p));
3456  }
3457  p+=GetPixelChannels(image);
3458  q+=GetPixelChannels(image);
3459  }
3460  }
3461  return(MagickTrue);
3462 }
3463 
3464 /*
3465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3466 % %
3467 % %
3468 % %
3469 + O p e n P i x e l C a c h e %
3470 % %
3471 % %
3472 % %
3473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3474 %
3475 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3476 % dimensions, allocating space for the image pixels and optionally the
3477 % metacontent, and memory mapping the cache if it is disk based. The cache
3478 % nexus array is initialized as well.
3479 %
3480 % The format of the OpenPixelCache() method is:
3481 %
3482 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3483 % ExceptionInfo *exception)
3484 %
3485 % A description of each parameter follows:
3486 %
3487 % o image: the image.
3488 %
3489 % o mode: ReadMode, WriteMode, or IOMode.
3490 %
3491 % o exception: return any errors or warnings in this structure.
3492 %
3493 */
3494 
3496  const MapMode mode)
3497 {
3498  int
3499  file;
3500 
3501  /*
3502  Open pixel cache on disk.
3503  */
3504  if ((cache_info->file != -1) && (cache_info->disk_mode == mode))
3505  return(MagickTrue); /* cache already open and in the proper mode */
3506  if (*cache_info->cache_filename == '\0')
3507  file=AcquireUniqueFileResource(cache_info->cache_filename);
3508  else
3509  switch (mode)
3510  {
3511  case ReadMode:
3512  {
3513  file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3514  break;
3515  }
3516  case WriteMode:
3517  {
3518  file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3519  O_BINARY | O_EXCL,S_MODE);
3520  if (file == -1)
3521  file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3522  break;
3523  }
3524  case IOMode:
3525  default:
3526  {
3527  file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3528  O_EXCL,S_MODE);
3529  if (file == -1)
3530  file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3531  break;
3532  }
3533  }
3534  if (file == -1)
3535  return(MagickFalse);
3537  if (cache_info->file != -1)
3538  (void) ClosePixelCacheOnDisk(cache_info);
3539  cache_info->file=file;
3540  cache_info->disk_mode=mode;
3541  return(MagickTrue);
3542 }
3543 
3545  const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3546  const MagickSizeType length,const unsigned char *magick_restrict buffer)
3547 {
3549  i;
3550 
3551  ssize_t
3552  count;
3553 
3554 #if !defined(MAGICKCORE_HAVE_PWRITE)
3555  if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3556  return((MagickOffsetType) -1);
3557 #endif
3558  count=0;
3559  for (i=0; i < (MagickOffsetType) length; i+=count)
3560  {
3561 #if !defined(MAGICKCORE_HAVE_PWRITE)
3562  count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3563  MAGICK_SSIZE_MAX));
3564 #else
3565  count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3566  MAGICK_SSIZE_MAX),offset+i);
3567 #endif
3568  if (count <= 0)
3569  {
3570  count=0;
3571  if (errno != EINTR)
3572  break;
3573  }
3574  }
3575  return(i);
3576 }
3577 
3579 {
3580  CacheInfo
3581  *magick_restrict cache_info;
3582 
3584  count,
3585  extent,
3586  offset;
3587 
3588  cache_info=(CacheInfo *) image->cache;
3589  if (image->debug != MagickFalse)
3590  {
3591  char
3592  format[MagickPathExtent],
3593  message[MagickPathExtent];
3594 
3595  (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3596  (void) FormatLocaleString(message,MagickPathExtent,
3597  "extend %s (%s[%d], disk, %s)",cache_info->filename,
3598  cache_info->cache_filename,cache_info->file,format);
3599  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3600  }
3601  if (length != (MagickSizeType) ((MagickOffsetType) length))
3602  return(MagickFalse);
3603  offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3604  if (offset < 0)
3605  return(MagickFalse);
3606  if ((MagickSizeType) offset >= length)
3607  count=(MagickOffsetType) 1;
3608  else
3609  {
3610  extent=(MagickOffsetType) length-1;
3611  count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3612  "");
3613  if (count != 1)
3614  return(MagickFalse);
3615 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3616  if (cache_info->synchronize != MagickFalse)
3617  if (posix_fallocate(cache_info->file,offset+1,extent-offset) != 0)
3618  return(MagickFalse);
3619 #endif
3620  }
3621  offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3622  if (offset < 0)
3623  return(MagickFalse);
3624  return(MagickTrue);
3625 }
3626 
3628  ExceptionInfo *exception)
3629 {
3630  CacheInfo
3631  *magick_restrict cache_info,
3632  source_info;
3633 
3634  char
3635  format[MagickPathExtent],
3636  message[MagickPathExtent];
3637 
3638  const char
3639  *hosts,
3640  *type;
3641 
3643  status;
3644 
3646  length,
3647  number_pixels;
3648 
3649  size_t
3650  columns,
3651  packet_size;
3652 
3653  assert(image != (const Image *) NULL);
3654  assert(image->signature == MagickCoreSignature);
3655  assert(image->cache != (Cache) NULL);
3656  if (image->debug != MagickFalse)
3657  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3658  if (cache_anonymous_memory < 0)
3659  {
3660  char
3661  *value;
3662 
3663  /*
3664  Does the security policy require anonymous mapping for pixel cache?
3665  */
3667  value=GetPolicyValue("pixel-cache-memory");
3668  if (value == (char *) NULL)
3669  value=GetPolicyValue("cache:memory-map");
3670  if (LocaleCompare(value,"anonymous") == 0)
3671  {
3672 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3674 #else
3675  (void) ThrowMagickException(exception,GetMagickModule(),
3676  MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3677  "'%s' (policy requires anonymous memory mapping)",image->filename);
3678 #endif
3679  }
3680  value=DestroyString(value);
3681  }
3682  if ((image->columns == 0) || (image->rows == 0))
3683  ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3684  cache_info=(CacheInfo *) image->cache;
3685  assert(cache_info->signature == MagickCoreSignature);
3686  if (((MagickSizeType) image->columns > cache_info->width_limit) ||
3687  ((MagickSizeType) image->rows > cache_info->height_limit))
3688  ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
3689  image->filename);
3691  {
3692  length=GetImageListLength(image);
3694  ThrowBinaryException(ResourceLimitError,"ListLengthExceedsLimit",
3695  image->filename);
3696  }
3697  source_info=(*cache_info);
3698  source_info.file=(-1);
3699  (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3700  image->filename,(double) image->scene);
3701  cache_info->storage_class=image->storage_class;
3702  cache_info->colorspace=image->colorspace;
3703  cache_info->alpha_trait=image->alpha_trait;
3704  cache_info->channels=image->channels;
3705  cache_info->rows=image->rows;
3706  cache_info->columns=image->columns;
3708  cache_info->number_channels=GetPixelChannels(image);
3709  (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3710  sizeof(*image->channel_map));
3711  cache_info->metacontent_extent=image->metacontent_extent;
3712  cache_info->mode=mode;
3713  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3714  packet_size=MagickMax(cache_info->number_channels,1)*sizeof(Quantum);
3715  if (image->metacontent_extent != 0)
3716  packet_size+=cache_info->metacontent_extent;
3717  length=number_pixels*packet_size;
3718  columns=(size_t) (length/cache_info->rows/packet_size);
3719  if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3720  ((ssize_t) cache_info->rows < 0))
3721  ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3722  image->filename);
3723  cache_info->length=length;
3724  if (image->ping != MagickFalse)
3725  {
3726  cache_info->type=PingCache;
3727  return(MagickTrue);
3728  }
3730  cache_info->columns*cache_info->rows);
3731  if (cache_info->mode == PersistMode)
3732  status=MagickFalse;
3733  length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3734  cache_info->metacontent_extent);
3735  if ((status != MagickFalse) &&
3736  (length == (MagickSizeType) ((size_t) length)) &&
3737  ((cache_info->type == UndefinedCache) ||
3738  (cache_info->type == MemoryCache)))
3739  {
3740  status=AcquireMagickResource(MemoryResource,cache_info->length);
3741  if (status != MagickFalse)
3742  {
3743  status=MagickTrue;
3744  if (cache_anonymous_memory <= 0)
3745  {
3746  cache_info->mapped=MagickFalse;
3747  cache_info->pixels=(Quantum *) MagickAssumeAligned(
3748  AcquireAlignedMemory(1,(size_t) cache_info->length));
3749  }
3750  else
3751  {
3752  cache_info->mapped=MagickTrue;
3753  cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3754  cache_info->length);
3755  }
3756  if (cache_info->pixels == (Quantum *) NULL)
3757  {
3758  cache_info->mapped=source_info.mapped;
3759  cache_info->pixels=source_info.pixels;
3760  }
3761  else
3762  {
3763  /*
3764  Create memory pixel cache.
3765  */
3766  cache_info->type=MemoryCache;
3767  cache_info->metacontent=(void *) NULL;
3768  if (cache_info->metacontent_extent != 0)
3769  cache_info->metacontent=(void *) (cache_info->pixels+
3770  cache_info->number_channels*number_pixels);
3771  if ((source_info.storage_class != UndefinedClass) &&
3772  (mode != ReadMode))
3773  {
3774  status=ClonePixelCacheRepository(cache_info,&source_info,
3775  exception);
3776  RelinquishPixelCachePixels(&source_info);
3777  }
3778  if (image->debug != MagickFalse)
3779  {
3780  (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3781  MagickPathExtent,format);
3783  cache_info->type);
3784  (void) FormatLocaleString(message,MagickPathExtent,
3785  "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3786  cache_info->filename,cache_info->mapped != MagickFalse ?
3787  "Anonymous" : "Heap",type,(double) cache_info->columns,
3788  (double) cache_info->rows,(double)
3789  cache_info->number_channels,format);
3791  message);
3792  }
3793  cache_info->storage_class=image->storage_class;
3794  if (status == 0)
3795  {
3796  cache_info->type=UndefinedCache;
3797  return(MagickFalse);
3798  }
3799  return(MagickTrue);
3800  }
3801  }
3802  }
3803  status=AcquireMagickResource(DiskResource,cache_info->length);
3804  hosts=(const char *) GetImageRegistry(StringRegistryType,"cache:hosts",
3805  exception);
3806  if ((status == MagickFalse) && (hosts != (const char *) NULL))
3807  {
3809  *server_info;
3810 
3811  /*
3812  Distribute the pixel cache to a remote server.
3813  */
3814  server_info=AcquireDistributeCacheInfo(exception);
3815  if (server_info != (DistributeCacheInfo *) NULL)
3816  {
3817  status=OpenDistributePixelCache(server_info,image);
3818  if (status == MagickFalse)
3819  {
3820  ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3821  GetDistributeCacheHostname(server_info));
3822  server_info=DestroyDistributeCacheInfo(server_info);
3823  }
3824  else
3825  {
3826  /*
3827  Create a distributed pixel cache.
3828  */
3829  status=MagickTrue;
3830  cache_info->type=DistributedCache;
3831  cache_info->server_info=server_info;
3832  (void) FormatLocaleString(cache_info->cache_filename,
3834  (DistributeCacheInfo *) cache_info->server_info),
3836  cache_info->server_info));
3837  if ((source_info.storage_class != UndefinedClass) &&
3838  (mode != ReadMode))
3839  {
3840  status=ClonePixelCacheRepository(cache_info,&source_info,
3841  exception);
3842  RelinquishPixelCachePixels(&source_info);
3843  }
3844  if (image->debug != MagickFalse)
3845  {
3846  (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3847  MagickPathExtent,format);
3849  cache_info->type);
3850  (void) FormatLocaleString(message,MagickPathExtent,
3851  "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3852  cache_info->filename,cache_info->cache_filename,
3854  cache_info->server_info),type,(double) cache_info->columns,
3855  (double) cache_info->rows,(double)
3856  cache_info->number_channels,format);
3858  message);
3859  }
3860  if (status == 0)
3861  {
3862  cache_info->type=UndefinedCache;
3863  return(MagickFalse);
3864  }
3865  return(MagickTrue);
3866  }
3867  }
3868  cache_info->type=UndefinedCache;
3869  (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3870  "CacheResourcesExhausted","`%s'",image->filename);
3871  return(MagickFalse);
3872  }
3873  /*
3874  Create pixel cache on disk.
3875  */
3876  if (status == MagickFalse)
3877  {
3878  cache_info->type=UndefinedCache;
3879  (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3880  "CacheResourcesExhausted","`%s'",image->filename);
3881  return(MagickFalse);
3882  }
3883  if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode) &&
3884  (cache_info->mode != PersistMode))
3885  {
3886  (void) ClosePixelCacheOnDisk(cache_info);
3887  *cache_info->cache_filename='\0';
3888  }
3889  if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3890  {
3891  cache_info->type=UndefinedCache;
3892  ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3893  image->filename);
3894  return(MagickFalse);
3895  }
3896  status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3897  cache_info->length);
3898  if (status == MagickFalse)
3899  {
3900  cache_info->type=UndefinedCache;
3901  ThrowFileException(exception,CacheError,"UnableToExtendCache",
3902  image->filename);
3903  return(MagickFalse);
3904  }
3905  cache_info->type=DiskCache;
3906  length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3907  cache_info->metacontent_extent);
3908  if (length == (MagickSizeType) ((size_t) length))
3909  {
3910  status=AcquireMagickResource(MapResource,cache_info->length);
3911  if (status != MagickFalse)
3912  {
3913  cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3914  cache_info->offset,(size_t) cache_info->length);
3915  if (cache_info->pixels == (Quantum *) NULL)
3916  {
3917  cache_info->mapped=source_info.mapped;
3918  cache_info->pixels=source_info.pixels;
3919  RelinquishMagickResource(MapResource,cache_info->length);
3920  }
3921  else
3922  {
3923  /*
3924  Create file-backed memory-mapped pixel cache.
3925  */
3926  (void) ClosePixelCacheOnDisk(cache_info);
3927  cache_info->type=MapCache;
3928  cache_info->mapped=MagickTrue;
3929  cache_info->metacontent=(void *) NULL;
3930  if (cache_info->metacontent_extent != 0)
3931  cache_info->metacontent=(void *) (cache_info->pixels+
3932  cache_info->number_channels*number_pixels);
3933  if ((source_info.storage_class != UndefinedClass) &&
3934  (mode != ReadMode))
3935  {
3936  status=ClonePixelCacheRepository(cache_info,&source_info,
3937  exception);
3938  RelinquishPixelCachePixels(&source_info);
3939  }
3940  if (image->debug != MagickFalse)
3941  {
3942  (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3943  MagickPathExtent,format);
3945  cache_info->type);
3946  (void) FormatLocaleString(message,MagickPathExtent,
3947  "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3948  cache_info->filename,cache_info->cache_filename,
3949  cache_info->file,type,(double) cache_info->columns,
3950  (double) cache_info->rows,(double)
3951  cache_info->number_channels,format);
3953  message);
3954  }
3955  if (status == 0)
3956  {
3957  cache_info->type=UndefinedCache;
3958  return(MagickFalse);
3959  }
3960  return(MagickTrue);
3961  }
3962  }
3963  }
3964  status=MagickTrue;
3965  if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3966  {
3967  status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3968  RelinquishPixelCachePixels(&source_info);
3969  }
3970  if (image->debug != MagickFalse)
3971  {
3972  (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3973  MagickPathExtent,format);
3975  cache_info->type);
3976  (void) FormatLocaleString(message,MagickPathExtent,
3977  "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3978  cache_info->cache_filename,cache_info->file,type,(double)
3979  cache_info->columns,(double) cache_info->rows,(double)
3980  cache_info->number_channels,format);
3981  (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3982  }
3983  if (status == 0)
3984  {
3985  cache_info->type=UndefinedCache;
3986  return(MagickFalse);
3987  }
3988  return(MagickTrue);
3989 }
3990 
3991 /*
3992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3993 % %
3994 % %
3995 % %
3996 + P e r s i s t P i x e l C a c h e %
3997 % %
3998 % %
3999 % %
4000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4001 %
4002 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4003 % persistent pixel cache is one that resides on disk and is not destroyed
4004 % when the program exits.
4005 %
4006 % The format of the PersistPixelCache() method is:
4007 %
4008 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4009 % const MagickBooleanType attach,MagickOffsetType *offset,
4010 % ExceptionInfo *exception)
4011 %
4012 % A description of each parameter follows:
4013 %
4014 % o image: the image.
4015 %
4016 % o filename: the persistent pixel cache filename.
4017 %
4018 % o attach: A value other than zero initializes the persistent pixel cache.
4019 %
4020 % o initialize: A value other than zero initializes the persistent pixel
4021 % cache.
4022 %
4023 % o offset: the offset in the persistent cache to store pixels.
4024 %
4025 % o exception: return any errors or warnings in this structure.
4026 %
4027 */
4029  const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4030  ExceptionInfo *exception)
4031 {
4032  CacheInfo
4033  *magick_restrict cache_info,
4034  *magick_restrict clone_info;
4035 
4037  status;
4038 
4039  ssize_t
4040  page_size;
4041 
4042  assert(image != (Image *) NULL);
4043  assert(image->signature == MagickCoreSignature);
4044  if (image->debug != MagickFalse)
4045  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4046  assert(image->cache != (void *) NULL);
4047  assert(filename != (const char *) NULL);
4048  assert(offset != (MagickOffsetType *) NULL);
4049  page_size=GetMagickPageSize();
4050  cache_info=(CacheInfo *) image->cache;
4051  assert(cache_info->signature == MagickCoreSignature);
4052 #if defined(MAGICKCORE_OPENCL_SUPPORT)
4053  CopyOpenCLBuffer(cache_info);
4054 #endif
4055  if (attach != MagickFalse)
4056  {
4057  /*
4058  Attach existing persistent pixel cache.
4059  */
4060  if (image->debug != MagickFalse)
4062  "attach persistent cache");
4063  (void) CopyMagickString(cache_info->cache_filename,filename,
4065  cache_info->type=MapCache;
4066  cache_info->offset=(*offset);
4067  if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4068  return(MagickFalse);
4069  *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4070  return(MagickTrue);
4071  }
4072  /*
4073  Clone persistent pixel cache.
4074  */
4075  status=AcquireMagickResource(DiskResource,cache_info->length);
4076  if (status == MagickFalse)
4077  {
4078  (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4079  "CacheResourcesExhausted","`%s'",image->filename);
4080  return(MagickFalse);
4081  }
4082  clone_info=(CacheInfo *) ClonePixelCache(cache_info);
4083  clone_info->type=DiskCache;
4084  (void) CopyMagickString(clone_info->cache_filename,filename,MagickPathExtent);
4085  clone_info->file=(-1);
4086  clone_info->storage_class=cache_info->storage_class;
4087  clone_info->colorspace=cache_info->colorspace;
4088  clone_info->alpha_trait=cache_info->alpha_trait;
4089  clone_info->channels=cache_info->channels;
4090  clone_info->columns=cache_info->columns;
4091  clone_info->rows=cache_info->rows;
4092  clone_info->number_channels=cache_info->number_channels;
4093  clone_info->metacontent_extent=cache_info->metacontent_extent;
4094  clone_info->mode=PersistMode;
4095  clone_info->length=cache_info->length;
4096  (void) memcpy(clone_info->channel_map,cache_info->channel_map,
4097  MaxPixelChannels*sizeof(*cache_info->channel_map));
4098  clone_info->offset=(*offset);
4099  status=ClonePixelCacheRepository(clone_info,cache_info,exception);
4100  *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4101  clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4102  return(status);
4103 }
4104 
4105 /*
4106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4107 % %
4108 % %
4109 % %
4110 + 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 %
4111 % %
4112 % %
4113 % %
4114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4115 %
4116 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4117 % defined by the region rectangle and returns a pointer to the region. This
4118 % region is subsequently transferred from the pixel cache with
4119 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4120 % pixels are transferred, otherwise a NULL is returned.
4121 %
4122 % The format of the QueueAuthenticPixelCacheNexus() method is:
4123 %
4124 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4125 % const ssize_t y,const size_t columns,const size_t rows,
4126 % const MagickBooleanType clone,NexusInfo *nexus_info,
4127 % ExceptionInfo *exception)
4128 %
4129 % A description of each parameter follows:
4130 %
4131 % o image: the image.
4132 %
4133 % o x,y,columns,rows: These values define the perimeter of a region of
4134 % pixels.
4135 %
4136 % o nexus_info: the cache nexus to set.
4137 %
4138 % o clone: clone the pixel cache.
4139 %
4140 % o exception: return any errors or warnings in this structure.
4141 %
4142 */
4144  const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4145  const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4146 {
4147  CacheInfo
4148  *magick_restrict cache_info;
4149 
4151  offset;
4152 
4154  number_pixels;
4155 
4156  Quantum
4157  *magick_restrict pixels;
4158 
4159  /*
4160  Validate pixel cache geometry.
4161  */
4162  assert(image != (const Image *) NULL);
4163  assert(image->signature == MagickCoreSignature);
4164  assert(image->cache != (Cache) NULL);
4165  cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4166  if (cache_info == (Cache) NULL)
4167  return((Quantum *) NULL);
4168  assert(cache_info->signature == MagickCoreSignature);
4169  if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
4170  (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4171  (y >= (ssize_t) cache_info->rows))
4172  {
4173  (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4174  "PixelsAreNotAuthentic","`%s'",image->filename);
4175  return((Quantum *) NULL);
4176  }
4177  offset=(MagickOffsetType) y*cache_info->columns+x;
4178  if (offset < 0)
4179  return((Quantum *) NULL);
4180  number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4181  offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4182  if ((MagickSizeType) offset >= number_pixels)
4183  return((Quantum *) NULL);
4184  /*
4185  Return pixel cache.
4186  */
4187  pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,x,y,columns,rows,
4188  ((image->channels & WriteMaskChannel) != 0) ||
4189  ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
4190  nexus_info,exception);
4191  return(pixels);
4192 }
4193 
4194 /*
4195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4196 % %
4197 % %
4198 % %
4199 + 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 %
4200 % %
4201 % %
4202 % %
4203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4204 %
4205 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4206 % defined by the region rectangle and returns a pointer to the region. This
4207 % region is subsequently transferred from the pixel cache with
4208 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4209 % pixels are transferred, otherwise a NULL is returned.
4210 %
4211 % The format of the QueueAuthenticPixelsCache() method is:
4212 %
4213 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4214 % const ssize_t y,const size_t columns,const size_t rows,
4215 % ExceptionInfo *exception)
4216 %
4217 % A description of each parameter follows:
4218 %
4219 % o image: the image.
4220 %
4221 % o x,y,columns,rows: These values define the perimeter of a region of
4222 % pixels.
4223 %
4224 % o exception: return any errors or warnings in this structure.
4225 %
4226 */
4227 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4228  const ssize_t y,const size_t columns,const size_t rows,
4229  ExceptionInfo *exception)
4230 {
4231  CacheInfo
4232  *magick_restrict cache_info;
4233 
4234  const int
4235  id = GetOpenMPThreadId();
4236 
4237  Quantum
4238  *magick_restrict pixels;
4239 
4240  assert(image != (const Image *) NULL);
4241  assert(image->signature == MagickCoreSignature);
4242  assert(image->cache != (Cache) NULL);
4243  cache_info=(CacheInfo *) image->cache;
4244  assert(cache_info->signature == MagickCoreSignature);
4245  assert(id < (int) cache_info->number_threads);
4246  pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4247  cache_info->nexus_info[id],exception);
4248  return(pixels);
4249 }
4250 
4251 /*
4252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4253 % %
4254 % %
4255 % %
4256 % Q u e u e A u t h e n t i c P i x e l s %
4257 % %
4258 % %
4259 % %
4260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4261 %
4262 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4263 % successfully initialized a pointer to a Quantum array representing the
4264 % region is returned, otherwise NULL is returned. The returned pointer may
4265 % point to a temporary working buffer for the pixels or it may point to the
4266 % final location of the pixels in memory.
4267 %
4268 % Write-only access means that any existing pixel values corresponding to
4269 % the region are ignored. This is useful if the initial image is being
4270 % created from scratch, or if the existing pixel values are to be
4271 % completely replaced without need to refer to their pre-existing values.
4272 % The application is free to read and write the pixel buffer returned by
4273 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4274 % initialize the pixel array values. Initializing pixel array values is the
4275 % application's responsibility.
4276 %
4277 % Performance is maximized if the selected region is part of one row, or
4278 % one or more full rows, since then there is opportunity to access the
4279 % pixels in-place (without a copy) if the image is in memory, or in a
4280 % memory-mapped file. The returned pointer must *never* be deallocated
4281 % by the user.
4282 %
4283 % Pixels accessed via the returned pointer represent a simple array of type
4284 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4285 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4286 % obtain the meta-content (of type void) corresponding to the region.
4287 % Once the Quantum (and/or Quantum) array has been updated, the
4288 % changes must be saved back to the underlying image using
4289 % SyncAuthenticPixels() or they may be lost.
4290 %
4291 % The format of the QueueAuthenticPixels() method is:
4292 %
4293 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4294 % const ssize_t y,const size_t columns,const size_t rows,
4295 % ExceptionInfo *exception)
4296 %
4297 % A description of each parameter follows:
4298 %
4299 % o image: the image.
4300 %
4301 % o x,y,columns,rows: These values define the perimeter of a region of
4302 % pixels.
4303 %
4304 % o exception: return any errors or warnings in this structure.
4305 %
4306 */
4308  const ssize_t y,const size_t columns,const size_t rows,
4309  ExceptionInfo *exception)
4310 {
4311  CacheInfo
4312  *magick_restrict cache_info;
4313 
4314  const int
4315  id = GetOpenMPThreadId();
4316 
4317  Quantum
4318  *magick_restrict pixels;
4319 
4320  assert(image != (Image *) NULL);
4321  assert(image->signature == MagickCoreSignature);
4322  assert(image->cache != (Cache) NULL);
4323  cache_info=(CacheInfo *) image->cache;
4324  assert(cache_info->signature == MagickCoreSignature);
4325  if (cache_info->methods.queue_authentic_pixels_handler !=
4327  {
4328  pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4329  columns,rows,exception);
4330  return(pixels);
4331  }
4332  assert(id < (int) cache_info->number_threads);
4333  pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4334  cache_info->nexus_info[id],exception);
4335  return(pixels);
4336 }
4337 
4338 /*
4339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4340 % %
4341 % %
4342 % %
4343 + 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 %
4344 % %
4345 % %
4346 % %
4347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4348 %
4349 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4350 % the pixel cache.
4351 %
4352 % The format of the ReadPixelCacheMetacontent() method is:
4353 %
4354 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4355 % NexusInfo *nexus_info,ExceptionInfo *exception)
4356 %
4357 % A description of each parameter follows:
4358 %
4359 % o cache_info: the pixel cache.
4360 %
4361 % o nexus_info: the cache nexus to read the metacontent.
4362 %
4363 % o exception: return any errors or warnings in this structure.
4364 %
4365 */
4366 
4368  const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4369  const MagickSizeType length,unsigned char *magick_restrict buffer)
4370 {
4372  i;
4373 
4374  ssize_t
4375  count;
4376 
4377 #if !defined(MAGICKCORE_HAVE_PREAD)
4378  if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4379  return((MagickOffsetType) -1);
4380 #endif
4381  count=0;
4382  for (i=0; i < (MagickOffsetType) length; i+=count)
4383  {
4384 #if !defined(MAGICKCORE_HAVE_PREAD)
4385  count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4386  MAGICK_SSIZE_MAX));
4387 #else
4388  count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4389  MAGICK_SSIZE_MAX),offset+i);
4390 #endif
4391  if (count <= 0)
4392  {
4393  count=0;
4394  if (errno != EINTR)
4395  break;
4396  }
4397  }
4398  return(i);
4399 }
4400 
4402  CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4403  ExceptionInfo *exception)
4404 {
4406  count,
4407  offset;
4408 
4410  extent,
4411  length;
4412 
4413  ssize_t
4414  y;
4415 
4416  unsigned char
4417  *magick_restrict q;
4418 
4419  size_t
4420  rows;
4421 
4422  if (cache_info->metacontent_extent == 0)
4423  return(MagickFalse);
4424  if (nexus_info->authentic_pixel_cache != MagickFalse)
4425  return(MagickTrue);
4426  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4427  nexus_info->region.x;
4428  length=(MagickSizeType) nexus_info->region.width*
4429  cache_info->metacontent_extent;
4430  extent=length*nexus_info->region.height;
4431  rows=nexus_info->region.height;
4432  y=0;
4433  q=(unsigned char *) nexus_info->metacontent;
4434  switch (cache_info->type)
4435  {
4436  case MemoryCache:
4437  case MapCache:
4438  {
4439  unsigned char
4440  *magick_restrict p;
4441 
4442  /*
4443  Read meta-content from memory.
4444  */
4445  if ((cache_info->columns == nexus_info->region.width) &&
4446  (extent == (MagickSizeType) ((size_t) extent)))
4447  {
4448  length=extent;
4449  rows=1UL;
4450  }
4451  p=(unsigned char *) cache_info->metacontent+offset*
4452  cache_info->metacontent_extent;
4453  for (y=0; y < (ssize_t) rows; y++)
4454  {
4455  (void) memcpy(q,p,(size_t) length);
4456  p+=cache_info->metacontent_extent*cache_info->columns;
4457  q+=cache_info->metacontent_extent*nexus_info->region.width;
4458  }
4459  break;
4460  }
4461  case DiskCache:
4462  {
4463  /*
4464  Read meta content from disk.
4465  */
4466  LockSemaphoreInfo(cache_info->file_semaphore);
4467  if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4468  {
4469  ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4470  cache_info->cache_filename);
4471  UnlockSemaphoreInfo(cache_info->file_semaphore);
4472  return(MagickFalse);
4473  }
4474  if ((cache_info->columns == nexus_info->region.width) &&
4475  (extent <= MagickMaxBufferExtent))
4476  {
4477  length=extent;
4478  rows=1UL;
4479  }
4480  extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4481  for (y=0; y < (ssize_t) rows; y++)
4482  {
4483  count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4484  cache_info->number_channels*sizeof(Quantum)+offset*
4485  cache_info->metacontent_extent,length,(unsigned char *) q);
4486  if (count != (MagickOffsetType) length)
4487  break;
4488  offset+=cache_info->columns;
4489  q+=cache_info->metacontent_extent*nexus_info->region.width;
4490  }
4492  (void) ClosePixelCacheOnDisk(cache_info);
4493  UnlockSemaphoreInfo(cache_info->file_semaphore);
4494  break;
4495  }
4496  case DistributedCache:
4497  {
4499  region;
4500 
4501  /*
4502  Read metacontent from distributed cache.
4503  */
4504  LockSemaphoreInfo(cache_info->file_semaphore);
4505  region=nexus_info->region;
4506  if ((cache_info->columns != nexus_info->region.width) ||
4507  (extent > MagickMaxBufferExtent))
4508  region.height=1UL;
4509  else
4510  {
4511  length=extent;
4512  rows=1UL;
4513  }
4514  for (y=0; y < (ssize_t) rows; y++)
4515  {
4517  cache_info->server_info,&region,length,(unsigned char *) q);
4518  if (count != (MagickOffsetType) length)
4519  break;
4520  q+=cache_info->metacontent_extent*nexus_info->region.width;
4521  region.y++;
4522  }
4523  UnlockSemaphoreInfo(cache_info->file_semaphore);
4524  break;
4525  }
4526  default:
4527  break;
4528  }
4529  if (y < (ssize_t) rows)
4530  {
4531  ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4532  cache_info->cache_filename);
4533  return(MagickFalse);
4534  }
4535  if ((cache_info->debug != MagickFalse) &&
4536  (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4538  "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4539  nexus_info->region.width,(double) nexus_info->region.height,(double)
4540  nexus_info->region.x,(double) nexus_info->region.y);
4541  return(MagickTrue);
4542 }
4543 
4544 /*
4545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4546 % %
4547 % %
4548 % %
4549 + R e a d P i x e l C a c h e P i x e l s %
4550 % %
4551 % %
4552 % %
4553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4554 %
4555 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4556 % cache.
4557 %
4558 % The format of the ReadPixelCachePixels() method is:
4559 %
4560 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4561 % NexusInfo *nexus_info,ExceptionInfo *exception)
4562 %
4563 % A description of each parameter follows:
4564 %
4565 % o cache_info: the pixel cache.
4566 %
4567 % o nexus_info: the cache nexus to read the pixels.
4568 %
4569 % o exception: return any errors or warnings in this structure.
4570 %
4571 */
4573  CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4574  ExceptionInfo *exception)
4575 {
4577  count,
4578  offset;
4579 
4581  extent,
4582  length;
4583 
4584  Quantum
4585  *magick_restrict q;
4586 
4587  ssize_t
4588  y;
4589 
4590  size_t
4591  number_channels,
4592  rows;
4593 
4594  if (nexus_info->authentic_pixel_cache != MagickFalse)
4595  return(MagickTrue);
4596  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns;
4597  if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4598  return(MagickFalse);
4599  offset+=nexus_info->region.x;
4600  number_channels=cache_info->number_channels;
4601  length=(MagickSizeType) number_channels*nexus_info->region.width*
4602  sizeof(Quantum);
4603  if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4604  return(MagickFalse);
4605  rows=nexus_info->region.height;
4606  extent=length*rows;
4607  if ((extent == 0) || ((extent/length) != rows))
4608  return(MagickFalse);
4609  y=0;
4610  q=nexus_info->pixels;
4611  switch (cache_info->type)
4612  {
4613  case MemoryCache:
4614  case MapCache:
4615  {
4616  Quantum
4617  *magick_restrict p;
4618 
4619  /*
4620  Read pixels from memory.
4621  */
4622  if ((cache_info->columns == nexus_info->region.width) &&
4623  (extent == (MagickSizeType) ((size_t) extent)))
4624  {
4625  length=extent;
4626  rows=1UL;
4627  }
4628  p=cache_info->pixels+cache_info->number_channels*offset;
4629  for (y=0; y < (ssize_t) rows; y++)
4630  {
4631  (void) memcpy(q,p,(size_t) length);
4632  p+=cache_info->number_channels*cache_info->columns;
4633  q+=cache_info->number_channels*nexus_info->region.width;
4634  }
4635  break;
4636  }
4637  case DiskCache:
4638  {
4639  /*
4640  Read pixels from disk.
4641  */
4642  LockSemaphoreInfo(cache_info->file_semaphore);
4643  if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4644  {
4645  ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4646  cache_info->cache_filename);
4647  UnlockSemaphoreInfo(cache_info->file_semaphore);
4648  return(MagickFalse);
4649  }
4650  if ((cache_info->columns == nexus_info->region.width) &&
4651  (extent <= MagickMaxBufferExtent))
4652  {
4653  length=extent;
4654  rows=1UL;
4655  }
4656  for (y=0; y < (ssize_t) rows; y++)
4657  {
4658  count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4659  cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4660  if (count != (MagickOffsetType) length)
4661  break;
4662  offset+=cache_info->columns;
4663  q+=cache_info->number_channels*nexus_info->region.width;
4664  }
4666  (void) ClosePixelCacheOnDisk(cache_info);
4667  UnlockSemaphoreInfo(cache_info->file_semaphore);
4668  break;
4669  }
4670  case DistributedCache:
4671  {
4673  region;
4674 
4675  /*
4676  Read pixels from distributed cache.
4677  */
4678  LockSemaphoreInfo(cache_info->file_semaphore);
4679  region=nexus_info->region;
4680  if ((cache_info->columns != nexus_info->region.width) ||
4681  (extent > MagickMaxBufferExtent))
4682  region.height=1UL;
4683  else
4684  {
4685  length=extent;
4686  rows=1UL;
4687  }
4688  for (y=0; y < (ssize_t) rows; y++)
4689  {
4691  cache_info->server_info,&region,length,(unsigned char *) q);
4692  if (count != (MagickOffsetType) length)
4693  break;
4694  q+=cache_info->number_channels*nexus_info->region.width;
4695  region.y++;
4696  }
4697  UnlockSemaphoreInfo(cache_info->file_semaphore);
4698  break;
4699  }
4700  default:
4701  break;
4702  }
4703  if (y < (ssize_t) rows)
4704  {
4705  ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4706  cache_info->cache_filename);
4707  return(MagickFalse);
4708  }
4709  if ((cache_info->debug != MagickFalse) &&
4710  (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4712  "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4713  nexus_info->region.width,(double) nexus_info->region.height,(double)
4714  nexus_info->region.x,(double) nexus_info->region.y);
4715  return(MagickTrue);
4716 }
4717 
4718 /*
4719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4720 % %
4721 % %
4722 % %
4723 + R e f e r e n c e P i x e l C a c h e %
4724 % %
4725 % %
4726 % %
4727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4728 %
4729 % ReferencePixelCache() increments the reference count associated with the
4730 % pixel cache returning a pointer to the cache.
4731 %
4732 % The format of the ReferencePixelCache method is:
4733 %
4734 % Cache ReferencePixelCache(Cache cache_info)
4735 %
4736 % A description of each parameter follows:
4737 %
4738 % o cache_info: the pixel cache.
4739 %
4740 */
4742 {
4743  CacheInfo
4744  *magick_restrict cache_info;
4745 
4746  assert(cache != (Cache *) NULL);
4747  cache_info=(CacheInfo *) cache;
4748  assert(cache_info->signature == MagickCoreSignature);
4749  LockSemaphoreInfo(cache_info->semaphore);
4750  cache_info->reference_count++;
4751  UnlockSemaphoreInfo(cache_info->semaphore);
4752  return(cache_info);
4753 }
4754 
4755 /*
4756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4757 % %
4758 % %
4759 % %
4760 + R e s e t P i x e l C a c h e C h a n n e l s %
4761 % %
4762 % %
4763 % %
4764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4765 %
4766 % ResetPixelCacheChannels() resets the pixel cache channels.
4767 %
4768 % The format of the ResetPixelCacheChannels method is:
4769 %
4770 % void ResetPixelCacheChannels(Image *)
4771 %
4772 % A description of each parameter follows:
4773 %
4774 % o image: the image.
4775 %
4776 */
4778 {
4779  CacheInfo
4780  *magick_restrict cache_info;
4781 
4782  assert(image != (const Image *) NULL);
4783  assert(image->signature == MagickCoreSignature);
4784  assert(image->cache != (Cache) NULL);
4785  cache_info=(CacheInfo *) image->cache;
4786  assert(cache_info->signature == MagickCoreSignature);
4787  cache_info->number_channels=GetPixelChannels(image);
4788 }
4789 
4790 /*
4791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4792 % %
4793 % %
4794 % %
4795 + 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 %
4796 % %
4797 % %
4798 % %
4799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4800 %
4801 % ResetCacheAnonymousMemory() resets the anonymous_memory value.
4802 %
4803 % The format of the ResetCacheAnonymousMemory method is:
4804 %
4805 % void ResetCacheAnonymousMemory(void)
4806 %
4807 */
4809 {
4811 }
4812 
4813 /*
4814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4815 % %
4816 % %
4817 % %
4818 + R e s e t P i x e l C a c h e E p o c h %
4819 % %
4820 % %
4821 % %
4822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4823 %
4824 % ResetPixelCacheEpoch() resets the pixel cache epoch.
4825 %
4826 % The format of the ResetPixelCacheEpoch method is:
4827 %
4828 % void ResetPixelCacheEpoch(void)
4829 %
4830 */
4832 {
4833  cache_epoch=0;
4834 }
4835 
4836 /*
4837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4838 % %
4839 % %
4840 % %
4841 + S e t P i x e l C a c h e M e t h o d s %
4842 % %
4843 % %
4844 % %
4845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4846 %
4847 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4848 %
4849 % The format of the SetPixelCacheMethods() method is:
4850 %
4851 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4852 %
4853 % A description of each parameter follows:
4854 %
4855 % o cache: the pixel cache.
4856 %
4857 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4858 %
4859 */
4861 {
4862  CacheInfo
4863  *magick_restrict cache_info;
4864 
4866  get_one_authentic_pixel_from_handler;
4867 
4869  get_one_virtual_pixel_from_handler;
4870 
4871  /*
4872  Set cache pixel methods.
4873  */
4874  assert(cache != (Cache) NULL);
4875  assert(cache_methods != (CacheMethods *) NULL);
4876  cache_info=(CacheInfo *) cache;
4877  assert(cache_info->signature == MagickCoreSignature);
4878  if (cache_info->debug != MagickFalse)
4880  cache_info->filename);
4881  if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4882  cache_info->methods.get_virtual_pixel_handler=
4883  cache_methods->get_virtual_pixel_handler;
4884  if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4885  cache_info->methods.destroy_pixel_handler=
4886  cache_methods->destroy_pixel_handler;
4887  if (cache_methods->get_virtual_metacontent_from_handler !=
4889  cache_info->methods.get_virtual_metacontent_from_handler=
4890  cache_methods->get_virtual_metacontent_from_handler;
4891  if (cache_methods->get_authentic_pixels_handler !=
4893  cache_info->methods.get_authentic_pixels_handler=
4894  cache_methods->get_authentic_pixels_handler;
4895  if (cache_methods->queue_authentic_pixels_handler !=
4897  cache_info->methods.queue_authentic_pixels_handler=
4898  cache_methods->queue_authentic_pixels_handler;
4899  if (cache_methods->sync_authentic_pixels_handler !=
4901  cache_info->methods.sync_authentic_pixels_handler=
4902  cache_methods->sync_authentic_pixels_handler;
4903  if (cache_methods->get_authentic_pixels_from_handler !=
4905  cache_info->methods.get_authentic_pixels_from_handler=
4906  cache_methods->get_authentic_pixels_from_handler;
4907  if (cache_methods->get_authentic_metacontent_from_handler !=
4909  cache_info->methods.get_authentic_metacontent_from_handler=
4911  get_one_virtual_pixel_from_handler=
4912  cache_info->methods.get_one_virtual_pixel_from_handler;
4913  if (get_one_virtual_pixel_from_handler !=
4915  cache_info->methods.get_one_virtual_pixel_from_handler=
4916  cache_methods->get_one_virtual_pixel_from_handler;
4917  get_one_authentic_pixel_from_handler=
4918  cache_methods->get_one_authentic_pixel_from_handler;
4919  if (get_one_authentic_pixel_from_handler !=
4921  cache_info->methods.get_one_authentic_pixel_from_handler=
4922  cache_methods->get_one_authentic_pixel_from_handler;
4923 }
4924 
4925 /*
4926 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4927 % %
4928 % %
4929 % %
4930 + S e t P i x e l C a c h e N e x u s P i x e l s %
4931 % %
4932 % %
4933 % %
4934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4935 %
4936 % SetPixelCacheNexusPixels() defines the region of the cache for the
4937 % specified cache nexus.
4938 %
4939 % The format of the SetPixelCacheNexusPixels() method is:
4940 %
4941 % Quantum SetPixelCacheNexusPixels(
4942 % const CacheInfo *magick_restrict cache_info,const MapMode mode,
4943 % const ssize_t x,const ssize_t y,const size_t width,const size_t height,
4944 % const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
4945 % ExceptionInfo *exception)
4946 %
4947 % A description of each parameter follows:
4948 %
4949 % o cache_info: the pixel cache.
4950 %
4951 % o mode: ReadMode, WriteMode, or IOMode.
4952 %
4953 % o x,y,width,height: define the region of this particular cache nexus.
4954 %
4955 % o buffered: if true, nexus pixels are buffered.
4956 %
4957 % o nexus_info: the cache nexus to set.
4958 %
4959 % o exception: return any errors or warnings in this structure.
4960 %
4961 */
4962 
4964  const CacheInfo *magick_restrict cache_info,const MagickSizeType length,
4965  NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
4966 {
4967  if (length != (MagickSizeType) ((size_t) length))
4968  {
4969  (void) ThrowMagickException(exception,GetMagickModule(),
4970  ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
4971  cache_info->filename);
4972  return(MagickFalse);
4973  }
4974  nexus_info->length=0;
4975  nexus_info->mapped=MagickFalse;
4976  if (cache_anonymous_memory <= 0)
4977  {
4978  nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4979  (size_t) length));
4980  if (nexus_info->cache != (Quantum *) NULL)
4981  (void) memset(nexus_info->cache,0,(size_t) length);
4982  }
4983  else
4984  {
4985  nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t) length);
4986  if (nexus_info->cache != (Quantum *) NULL)
4987  nexus_info->mapped=MagickTrue;
4988  }
4989  if (nexus_info->cache == (Quantum *) NULL)
4990  {
4991  (void) ThrowMagickException(exception,GetMagickModule(),
4992  ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
4993  cache_info->filename);
4994  return(MagickFalse);
4995  }
4996  nexus_info->length=length;
4997  return(MagickTrue);
4998 }
4999 
5000 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
5001  const MapMode mode)
5002 {
5003  if (nexus_info->length < CACHE_LINE_SIZE)
5004  return;
5005  if (mode == ReadMode)
5006  {
5007  MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,
5008  0,1);
5009  return;
5010  }
5011  MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,1,1);
5012 }
5013 
5014 static inline MagickBooleanType ValidatePixelOffset(const ssize_t x,
5015  const size_t a)
5016 {
5017  if ((x >= 0) && (x >= ((ssize_t) MAGICK_SSIZE_MAX-(ssize_t) a)))
5018  return(MagickFalse);
5019  if (x <= ((ssize_t) MAGICK_SSIZE_MIN+(ssize_t) a))
5020  return(MagickFalse);
5021  return(MagickTrue);
5022 }
5023 
5025  const CacheInfo *magick_restrict cache_info,const MapMode mode,
5026  const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5027  const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5028  ExceptionInfo *exception)
5029 {
5031  status;
5032 
5034  length,
5035  number_pixels;
5036 
5037  assert(cache_info != (const CacheInfo *) NULL);
5038  assert(cache_info->signature == MagickCoreSignature);
5039  if (cache_info->type == UndefinedCache)
5040  return((Quantum *) NULL);
5041  assert(nexus_info->signature == MagickCoreSignature);
5042  (void) memset(&nexus_info->region,0,sizeof(nexus_info->region));
5043  if ((width == 0) || (height == 0))
5044  {
5045  (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
5046  "NoPixelsDefinedInCache","`%s'",cache_info->filename);
5047  return((Quantum *) NULL);
5048  }
5049  if (((MagickSizeType) width > cache_info->width_limit) ||
5050  ((MagickSizeType) height > cache_info->height_limit) ||
5051  (ValidatePixelOffset(x,width) == MagickFalse) ||
5052  (ValidatePixelOffset(y,height) == MagickFalse))
5053  {
5054  (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
5055  "WidthOrHeightExceedsLimit","`%s'",cache_info->filename);
5056  return((Quantum *) NULL);
5057  }
5058  if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
5059  (buffered == MagickFalse))
5060  {
5061  if (((x >= 0) && (y >= 0) &&
5062  (((ssize_t) height+y-1) < (ssize_t) cache_info->rows)) &&
5063  (((x == 0) && (width == cache_info->columns)) || ((height == 1) &&
5064  (((ssize_t) width+x-1) < (ssize_t) cache_info->columns))))
5065  {
5067  offset;
5068 
5069  /*
5070  Pixels are accessed directly from memory.
5071  */
5072  offset=(MagickOffsetType) y*cache_info->columns+x;
5073  nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5074  offset;
5075  nexus_info->metacontent=(void *) NULL;
5076  if (cache_info->metacontent_extent != 0)
5077  nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5078  offset*cache_info->metacontent_extent;
5079  nexus_info->region.width=width;
5080  nexus_info->region.height=height;
5081  nexus_info->region.x=x;
5082  nexus_info->region.y=y;
5083  nexus_info->authentic_pixel_cache=MagickTrue;
5084  PrefetchPixelCacheNexusPixels(nexus_info,mode);
5085  return(nexus_info->pixels);
5086  }
5087  }
5088  /*
5089  Pixels are stored in a staging region until they are synced to the cache.
5090  */
5091  number_pixels=(MagickSizeType) width*height;
5092  length=MagickMax(number_pixels,MagickMax(cache_info->columns,
5093  cache_info->rows))*cache_info->number_channels*sizeof(*nexus_info->pixels);
5094  if (cache_info->metacontent_extent != 0)
5095  length+=number_pixels*cache_info->metacontent_extent;
5096  status=MagickTrue;
5097  if (nexus_info->cache == (Quantum *) NULL)
5098  status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5099  else
5100  if (nexus_info->length < length)
5101  {
5102  RelinquishCacheNexusPixels(nexus_info);
5103  status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5104  }
5105  if (status == MagickFalse)
5106  return((Quantum *) NULL);
5107  nexus_info->pixels=nexus_info->cache;
5108  nexus_info->metacontent=(void *) NULL;
5109  if (cache_info->metacontent_extent != 0)
5110  nexus_info->metacontent=(void *) (nexus_info->pixels+
5111  cache_info->number_channels*number_pixels);
5112  nexus_info->region.width=width;
5113  nexus_info->region.height=height;
5114  nexus_info->region.x=x;
5115  nexus_info->region.y=y;
5116  nexus_info->authentic_pixel_cache=cache_info->type == PingCache ?
5118  PrefetchPixelCacheNexusPixels(nexus_info,mode);
5119  return(nexus_info->pixels);
5120 }
5121 
5122 /*
5123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5124 % %
5125 % %
5126 % %
5127 % 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 %
5128 % %
5129 % %
5130 % %
5131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5132 %
5133 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5134 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5135 % access that is outside the boundaries of the image cache.
5136 %
5137 % The format of the SetPixelCacheVirtualMethod() method is:
5138 %
5139 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5140 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5141 %
5142 % A description of each parameter follows:
5143 %
5144 % o image: the image.
5145 %
5146 % o virtual_pixel_method: choose the type of virtual pixel.
5147 %
5148 % o exception: return any errors or warnings in this structure.
5149 %
5150 */
5151 
5153  ExceptionInfo *exception)
5154 {
5155  CacheInfo
5156  *magick_restrict cache_info;
5157 
5158  CacheView
5159  *magick_restrict image_view;
5160 
5162  status;
5163 
5164  ssize_t
5165  y;
5166 
5167  assert(image != (Image *) NULL);
5168  assert(image->signature == MagickCoreSignature);
5169  if (image->debug != MagickFalse)
5170  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5171  assert(image->cache != (Cache) NULL);
5172  cache_info=(CacheInfo *) image->cache;
5173  assert(cache_info->signature == MagickCoreSignature);
5175  status=MagickTrue;
5176  image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
5177 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5178  #pragma omp parallel for schedule(static) shared(status) \
5179  magick_number_threads(image,image,image->rows,1)
5180 #endif
5181  for (y=0; y < (ssize_t) image->rows; y++)
5182  {
5183  Quantum
5184  *magick_restrict q;
5185 
5186  ssize_t
5187  x;
5188 
5189  if (status == MagickFalse)
5190  continue;
5191  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5192  if (q == (Quantum *) NULL)
5193  {
5194  status=MagickFalse;
5195  continue;
5196  }
5197  for (x=0; x < (ssize_t) image->columns; x++)
5198  {
5199  SetPixelAlpha(image,alpha,q);
5200  q+=GetPixelChannels(image);
5201  }
5202  status=SyncCacheViewAuthenticPixels(image_view,exception);
5203  }
5204  image_view=DestroyCacheView(image_view);
5205  return(status);
5206 }
5207 
5209  const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5210 {
5211  CacheInfo
5212  *magick_restrict cache_info;
5213 
5215  method;
5216 
5217  assert(image != (Image *) NULL);
5218  assert(image->signature == MagickCoreSignature);
5219  if (image->debug != MagickFalse)
5220  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5221  assert(image->cache != (Cache) NULL);
5222  cache_info=(CacheInfo *) image->cache;
5223  assert(cache_info->signature == MagickCoreSignature);
5224  method=cache_info->virtual_pixel_method;
5225  cache_info->virtual_pixel_method=virtual_pixel_method;
5226  if ((image->columns != 0) && (image->rows != 0))
5227  switch (virtual_pixel_method)
5228  {
5230  {
5232  (image->alpha_trait == UndefinedPixelTrait))
5233  (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5234  if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
5236  (void) SetImageColorspace(image,sRGBColorspace,exception);
5237  break;
5238  }
5240  {
5241  if (image->alpha_trait == UndefinedPixelTrait)
5242  (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5243  break;
5244  }
5245  default:
5246  break;
5247  }
5248  return(method);
5249 }
5250 
5251 #if defined(MAGICKCORE_OPENCL_SUPPORT)
5252 /*
5253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5254 % %
5255 % %
5256 % %
5257 + 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 %
5258 % %
5259 % %
5260 % %
5261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5262 %
5263 % SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
5264 % been completed and updates the host memory.
5265 %
5266 % The format of the SyncAuthenticOpenCLBuffer() method is:
5267 %
5268 % void SyncAuthenticOpenCLBuffer(const Image *image)
5269 %
5270 % A description of each parameter follows:
5271 %
5272 % o image: the image.
5273 %
5274 */
5275 
5276 static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5277 {
5278  assert(cache_info != (CacheInfo *) NULL);
5279  assert(cache_info->signature == MagickCoreSignature);
5280  if ((cache_info->type != MemoryCache) ||
5281  (cache_info->opencl == (MagickCLCacheInfo) NULL))
5282  return;
5283  /*
5284  Ensure single threaded access to OpenCL environment.
5285  */
5286  LockSemaphoreInfo(cache_info->semaphore);
5287  cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
5288  UnlockSemaphoreInfo(cache_info->semaphore);
5289 }
5290 
5291 MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5292 {
5293  CacheInfo
5294  *magick_restrict cache_info;
5295 
5296  assert(image != (const Image *) NULL);
5297  cache_info=(CacheInfo *) image->cache;
5298  CopyOpenCLBuffer(cache_info);
5299 }
5300 #endif
5301 
5302 /*
5303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5304 % %
5305 % %
5306 % %
5307 + 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 %
5308 % %
5309 % %
5310 % %
5311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5312 %
5313 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5314 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5315 % is synced, otherwise MagickFalse.
5316 %
5317 % The format of the SyncAuthenticPixelCacheNexus() method is:
5318 %
5319 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5320 % NexusInfo *nexus_info,ExceptionInfo *exception)
5321 %
5322 % A description of each parameter follows:
5323 %
5324 % o image: the image.
5325 %
5326 % o nexus_info: the cache nexus to sync.
5327 %
5328 % o exception: return any errors or warnings in this structure.
5329 %
5330 */
5332  NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5333 {
5334  CacheInfo
5335  *magick_restrict cache_info;
5336 
5338  status;
5339 
5340  /*
5341  Transfer pixels to the cache.
5342  */
5343  assert(image != (Image *) NULL);
5344  assert(image->signature == MagickCoreSignature);
5345  if (image->cache == (Cache) NULL)
5346  ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5347  cache_info=(CacheInfo *) image->cache;
5348  assert(cache_info->signature == MagickCoreSignature);
5349  if (cache_info->type == UndefinedCache)
5350  return(MagickFalse);
5351  if (image->mask_trait != UpdatePixelTrait)
5352  {
5353  if (((image->channels & WriteMaskChannel) != 0) &&
5354  (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5355  return(MagickFalse);
5356  if (((image->channels & CompositeMaskChannel) != 0) &&
5357  (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5358  return(MagickFalse);
5359  }
5360  if (nexus_info->authentic_pixel_cache != MagickFalse)
5361  {
5362  if (image->taint == MagickFalse)
5363  image->taint=MagickTrue;
5364  return(MagickTrue);
5365  }
5366  assert(cache_info->signature == MagickCoreSignature);
5367  status=WritePixelCachePixels(cache_info,nexus_info,exception);
5368  if ((cache_info->metacontent_extent != 0) &&
5369  (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5370  return(MagickFalse);
5371  if ((status != MagickFalse) && (image->taint == MagickFalse))
5372  image->taint=MagickTrue;
5373  return(status);
5374 }
5375 
5376 /*
5377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5378 % %
5379 % %
5380 % %
5381 + S y n c A u t h e n t i c P i x e l C a c h e %
5382 % %
5383 % %
5384 % %
5385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5386 %
5387 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5388 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5389 % otherwise MagickFalse.
5390 %
5391 % The format of the SyncAuthenticPixelsCache() method is:
5392 %
5393 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5394 % ExceptionInfo *exception)
5395 %
5396 % A description of each parameter follows:
5397 %
5398 % o image: the image.
5399 %
5400 % o exception: return any errors or warnings in this structure.
5401 %
5402 */
5404  ExceptionInfo *exception)
5405 {
5406  CacheInfo
5407  *magick_restrict cache_info;
5408 
5409  const int
5410  id = GetOpenMPThreadId();
5411 
5413  status;
5414 
5415  assert(image != (Image *) NULL);
5416  assert(image->signature == MagickCoreSignature);
5417  assert(image->cache != (Cache) NULL);
5418  cache_info=(CacheInfo *) image->cache;
5419  assert(cache_info->signature == MagickCoreSignature);
5420  assert(id < (int) cache_info->number_threads);
5421  status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5422  exception);
5423  return(status);
5424 }
5425 
5426 /*
5427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5428 % %
5429 % %
5430 % %
5431 % S y n c A u t h e n t i c P i x e l s %
5432 % %
5433 % %
5434 % %
5435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5436 %
5437 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5438 % The method returns MagickTrue if the pixel region is flushed, otherwise
5439 % MagickFalse.
5440 %
5441 % The format of the SyncAuthenticPixels() method is:
5442 %
5443 % MagickBooleanType SyncAuthenticPixels(Image *image,
5444 % ExceptionInfo *exception)
5445 %
5446 % A description of each parameter follows:
5447 %
5448 % o image: the image.
5449 %
5450 % o exception: return any errors or warnings in this structure.
5451 %
5452 */
5454  ExceptionInfo *exception)
5455 {
5456  CacheInfo
5457  *magick_restrict cache_info;
5458 
5459  const int
5460  id = GetOpenMPThreadId();
5461 
5463  status;
5464 
5465  assert(image != (Image *) NULL);
5466  assert(image->signature == MagickCoreSignature);
5467  assert(image->cache != (Cache) NULL);
5468  cache_info=(CacheInfo *) image->cache;
5469  assert(cache_info->signature == MagickCoreSignature);
5470  if (cache_info->methods.sync_authentic_pixels_handler != (SyncAuthenticPixelsHandler) NULL)
5471  {
5472  status=cache_info->methods.sync_authentic_pixels_handler(image,
5473  exception);
5474  return(status);
5475  }
5476  assert(id < (int) cache_info->number_threads);
5477  status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5478  exception);
5479  return(status);
5480 }
5481 
5482 /*
5483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5484 % %
5485 % %
5486 % %
5487 + S y n c I m a g e P i x e l C a c h e %
5488 % %
5489 % %
5490 % %
5491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5492 %
5493 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5494 % The method returns MagickTrue if the pixel region is flushed, otherwise
5495 % MagickFalse.
5496 %
5497 % The format of the SyncImagePixelCache() method is:
5498 %
5499 % MagickBooleanType SyncImagePixelCache(Image *image,
5500 % ExceptionInfo *exception)
5501 %
5502 % A description of each parameter follows:
5503 %
5504 % o image: the image.
5505 %
5506 % o exception: return any errors or warnings in this structure.
5507 %
5508 */
5510  ExceptionInfo *exception)
5511 {
5512  CacheInfo
5513  *magick_restrict cache_info;
5514 
5515  assert(image != (Image *) NULL);
5516  assert(exception != (ExceptionInfo *) NULL);
5517  cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5518  return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5519 }
5520 
5521 /*
5522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5523 % %
5524 % %
5525 % %
5526 + 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 %
5527 % %
5528 % %
5529 % %
5530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5531 %
5532 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5533 % of the pixel cache.
5534 %
5535 % The format of the WritePixelCacheMetacontent() method is:
5536 %
5537 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5538 % NexusInfo *nexus_info,ExceptionInfo *exception)
5539 %
5540 % A description of each parameter follows:
5541 %
5542 % o cache_info: the pixel cache.
5543 %
5544 % o nexus_info: the cache nexus to write the meta-content.
5545 %
5546 % o exception: return any errors or warnings in this structure.
5547 %
5548 */
5550  NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5551 {
5553  count,
5554  offset;
5555 
5557  extent,
5558  length;
5559 
5560  const unsigned char
5561  *magick_restrict p;
5562 
5563  ssize_t
5564  y;
5565 
5566  size_t
5567  rows;
5568 
5569  if (cache_info->metacontent_extent == 0)
5570  return(MagickFalse);
5571  if (nexus_info->authentic_pixel_cache != MagickFalse)
5572  return(MagickTrue);
5573  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5574  nexus_info->region.x;
5575  length=(MagickSizeType) nexus_info->region.width*
5576  cache_info->metacontent_extent;
5577  extent=(MagickSizeType) length*nexus_info->region.height;
5578  rows=nexus_info->region.height;
5579  y=0;
5580  p=(unsigned char *) nexus_info->metacontent;
5581  switch (cache_info->type)
5582  {
5583  case MemoryCache:
5584  case MapCache:
5585  {
5586  unsigned char
5587  *magick_restrict q;
5588 
5589  /*
5590  Write associated pixels to memory.
5591  */
5592  if ((cache_info->columns == nexus_info->region.width) &&
5593  (extent == (MagickSizeType) ((size_t) extent)))
5594  {
5595  length=extent;
5596  rows=1UL;
5597  }
5598  q=(unsigned char *) cache_info->metacontent+offset*
5599  cache_info->metacontent_extent;
5600  for (y=0; y < (ssize_t) rows; y++)
5601  {
5602  (void) memcpy(q,p,(size_t) length);
5603  p+=nexus_info->region.width*cache_info->metacontent_extent;
5604  q+=cache_info->columns*cache_info->metacontent_extent;
5605  }
5606  break;
5607  }
5608  case DiskCache:
5609  {
5610  /*
5611  Write associated pixels to disk.
5612  */
5613  LockSemaphoreInfo(cache_info->file_semaphore);
5614  if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5615  {
5616  ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5617  cache_info->cache_filename);
5618  UnlockSemaphoreInfo(cache_info->file_semaphore);
5619  return(MagickFalse);
5620  }
5621  if ((cache_info->columns == nexus_info->region.width) &&
5622  (extent <= MagickMaxBufferExtent))
5623  {
5624  length=extent;
5625  rows=1UL;
5626  }
5627  extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5628  for (y=0; y < (ssize_t) rows; y++)
5629  {
5630  count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5631  cache_info->number_channels*sizeof(Quantum)+offset*
5632  cache_info->metacontent_extent,length,(const unsigned char *) p);
5633  if (count != (MagickOffsetType) length)
5634  break;
5635  p+=cache_info->metacontent_extent*nexus_info->region.width;
5636  offset+=cache_info->columns;
5637  }
5639  (void) ClosePixelCacheOnDisk(cache_info);
5640  UnlockSemaphoreInfo(cache_info->file_semaphore);
5641  break;
5642  }
5643  case DistributedCache:
5644  {
5646  region;
5647 
5648  /*
5649  Write metacontent to distributed cache.
5650  */
5651  LockSemaphoreInfo(cache_info->file_semaphore);
5652  region=nexus_info->region;
5653  if ((cache_info->columns != nexus_info->region.width) ||
5654  (extent > MagickMaxBufferExtent))
5655  region.height=1UL;
5656  else
5657  {
5658  length=extent;
5659  rows=1UL;
5660  }
5661  for (y=0; y < (ssize_t) rows; y++)
5662  {
5664  cache_info->server_info,&region,length,(const unsigned char *) p);
5665  if (count != (MagickOffsetType) length)
5666  break;
5667  p+=cache_info->metacontent_extent*nexus_info->region.width;
5668  region.y++;
5669  }
5670  UnlockSemaphoreInfo(cache_info->file_semaphore);
5671  break;
5672  }
5673  default:
5674  break;
5675  }
5676  if (y < (ssize_t) rows)
5677  {
5678  ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5679  cache_info->cache_filename);
5680  return(MagickFalse);
5681  }
5682  if ((cache_info->debug != MagickFalse) &&
5683  (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5685  "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5686  nexus_info->region.width,(double) nexus_info->region.height,(double)
5687  nexus_info->region.x,(double) nexus_info->region.y);
5688  return(MagickTrue);
5689 }
5690 
5691 /*
5692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5693 % %
5694 % %
5695 % %
5696 + W r i t e C a c h e P i x e l s %
5697 % %
5698 % %
5699 % %
5700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5701 %
5702 % WritePixelCachePixels() writes image pixels to the specified region of the
5703 % pixel cache.
5704 %
5705 % The format of the WritePixelCachePixels() method is:
5706 %
5707 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5708 % NexusInfo *nexus_info,ExceptionInfo *exception)
5709 %
5710 % A description of each parameter follows:
5711 %
5712 % o cache_info: the pixel cache.
5713 %
5714 % o nexus_info: the cache nexus to write the pixels.
5715 %
5716 % o exception: return any errors or warnings in this structure.
5717 %
5718 */
5720  CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5721  ExceptionInfo *exception)
5722 {
5724  count,
5725  offset;
5726 
5728  extent,
5729  length;
5730 
5731  const Quantum
5732  *magick_restrict p;
5733 
5734  ssize_t
5735  y;
5736 
5737  size_t
5738  rows;
5739 
5740  if (nexus_info->authentic_pixel_cache != MagickFalse)
5741  return(MagickTrue);
5742  offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5743  nexus_info->region.x;
5744  length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5745  sizeof(Quantum);
5746  extent=length*nexus_info->region.height;
5747  rows=nexus_info->region.height;
5748  y=0;
5749  p=nexus_info->pixels;
5750  switch (cache_info->type)
5751  {
5752  case MemoryCache:
5753  case MapCache:
5754  {
5755  Quantum
5756  *magick_restrict q;
5757 
5758  /*
5759  Write pixels to memory.
5760  */
5761  if ((cache_info->columns == nexus_info->region.width) &&
5762  (extent == (MagickSizeType) ((size_t) extent)))
5763  {
5764  length=extent;
5765  rows=1UL;
5766  }
5767  q=cache_info->pixels+cache_info->number_channels*offset;
5768  for (y=0; y < (ssize_t) rows; y++)
5769  {
5770  (void) memcpy(q,p,(size_t) length);
5771  p+=cache_info->number_channels*nexus_info->region.width;
5772  q+=cache_info->number_channels*cache_info->columns;
5773  }
5774  break;
5775  }
5776  case DiskCache:
5777  {
5778  /*
5779  Write pixels to disk.
5780  */
5781  LockSemaphoreInfo(cache_info->file_semaphore);
5782  if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5783  {
5784  ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5785  cache_info->cache_filename);
5786  UnlockSemaphoreInfo(cache_info->file_semaphore);
5787  return(MagickFalse);
5788  }
5789  if ((cache_info->columns == nexus_info->region.width) &&
5790  (extent <= MagickMaxBufferExtent))
5791  {
5792  length=extent;
5793  rows=1UL;
5794  }
5795  for (y=0; y < (ssize_t) rows; y++)
5796  {
5797  count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5798  cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5799  p);
5800  if (count != (MagickOffsetType) length)
5801  break;
5802  p+=cache_info->number_channels*nexus_info->region.width;
5803  offset+=cache_info->columns;
5804  }
5806  (void) ClosePixelCacheOnDisk(cache_info);
5807  UnlockSemaphoreInfo(cache_info->file_semaphore);
5808  break;
5809  }
5810  case DistributedCache:
5811  {
5813  region;
5814 
5815  /*
5816  Write pixels to distributed cache.
5817  */
5818  LockSemaphoreInfo(cache_info->file_semaphore);
5819  region=nexus_info->region;
5820  if ((cache_info->columns != nexus_info->region.width) ||
5821  (extent > MagickMaxBufferExtent))
5822  region.height=1UL;
5823  else
5824  {
5825  length=extent;
5826  rows=1UL;