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