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