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