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