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