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