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