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