MagickCore 7.1.2-32
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;
103} MagickModulo;
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{
193 CacheInfo
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{
264 NexusInfo
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{
320 CacheInfo
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{
421 CacheInfo
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{
522 CacheInfo
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{
566 CacheInfo
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
736 NexusInfo
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{
980 CacheInfo
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{
2817 MagickModulo
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 {
3036 MagickModulo
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 {
3962 DistributeCacheInfo
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 (IsValidPixelOffset(y,cache_info->columns) == MagickFalse)
4357 return((Quantum *) NULL);
4358 offset=y*(MagickOffsetType) cache_info->columns;
4359 if (IsOffsetOverflow(offset,(MagickOffsetType) x) == MagickFalse)
4360 return((Quantum *) NULL);
4361 offset+=x;
4362 if (offset < 0)
4363 return((Quantum *) NULL);
4364 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4365 offset+=((MagickOffsetType) rows-1)*(MagickOffsetType) cache_info->columns;
4366 if (IsOffsetOverflow(offset,(MagickOffsetType) columns-1) == MagickFalse)
4367 return((Quantum *) NULL);
4368 offset+=(MagickOffsetType) columns-1;
4369 if ((MagickSizeType) offset >= number_pixels)
4370 return((Quantum *) NULL);
4371 /*
4372 Return pixel cache.
4373 */
4374 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,x,y,columns,rows,
4375 ((image->channels & WriteMaskChannel) != 0) ||
4376 ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
4377 nexus_info,exception);
4378 return(pixels);
4379}
4380␌
4381/*
4382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4383% %
4384% %
4385% %
4386+ 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 %
4387% %
4388% %
4389% %
4390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4391%
4392% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4393% defined by the region rectangle and returns a pointer to the region. This
4394% region is subsequently transferred from the pixel cache with
4395% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4396% pixels are transferred, otherwise a NULL is returned.
4397%
4398% The format of the QueueAuthenticPixelsCache() method is:
4399%
4400% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4401% const ssize_t y,const size_t columns,const size_t rows,
4402% ExceptionInfo *exception)
4403%
4404% A description of each parameter follows:
4405%
4406% o image: the image.
4407%
4408% o x,y,columns,rows: These values define the perimeter of a region of
4409% pixels.
4410%
4411% o exception: return any errors or warnings in this structure.
4412%
4413*/
4414static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4415 const ssize_t y,const size_t columns,const size_t rows,
4416 ExceptionInfo *exception)
4417{
4418 CacheInfo
4419 *magick_restrict cache_info;
4420
4421 const int
4422 id = GetOpenMPThreadId();
4423
4424 Quantum
4425 *magick_restrict pixels;
4426
4427 assert(image != (const Image *) NULL);
4428 assert(image->signature == MagickCoreSignature);
4429 assert(image->cache != (Cache) NULL);
4430 cache_info=(CacheInfo *) image->cache;
4431 assert(cache_info->signature == MagickCoreSignature);
4432 assert(id < (int) cache_info->number_threads);
4433 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4434 cache_info->nexus_info[id],exception);
4435 return(pixels);
4436}
4437␌
4438/*
4439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4440% %
4441% %
4442% %
4443% Q u e u e A u t h e n t i c P i x e l s %
4444% %
4445% %
4446% %
4447%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4448%
4449% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4450% successfully initialized a pointer to a Quantum array representing the
4451% region is returned, otherwise NULL is returned. The returned pointer may
4452% point to a temporary working buffer for the pixels or it may point to the
4453% final location of the pixels in memory.
4454%
4455% Write-only access means that any existing pixel values corresponding to
4456% the region are ignored. This is useful if the initial image is being
4457% created from scratch, or if the existing pixel values are to be
4458% completely replaced without need to refer to their preexisting values.
4459% The application is free to read and write the pixel buffer returned by
4460% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4461% initialize the pixel array values. Initializing pixel array values is the
4462% application's responsibility.
4463%
4464% Performance is maximized if the selected region is part of one row, or
4465% one or more full rows, since then there is opportunity to access the
4466% pixels in-place (without a copy) if the image is in memory, or in a
4467% memory-mapped file. The returned pointer must *never* be deallocated
4468% by the user.
4469%
4470% Pixels accessed via the returned pointer represent a simple array of type
4471% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4472% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4473% obtain the meta-content (of type void) corresponding to the region.
4474% Once the Quantum (and/or Quantum) array has been updated, the
4475% changes must be saved back to the underlying image using
4476% SyncAuthenticPixels() or they may be lost.
4477%
4478% The format of the QueueAuthenticPixels() method is:
4479%
4480% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4481% const ssize_t y,const size_t columns,const size_t rows,
4482% ExceptionInfo *exception)
4483%
4484% A description of each parameter follows:
4485%
4486% o image: the image.
4487%
4488% o x,y,columns,rows: These values define the perimeter of a region of
4489% pixels.
4490%
4491% o exception: return any errors or warnings in this structure.
4492%
4493*/
4494MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4495 const ssize_t y,const size_t columns,const size_t rows,
4496 ExceptionInfo *exception)
4497{
4498 CacheInfo
4499 *magick_restrict cache_info;
4500
4501 const int
4502 id = GetOpenMPThreadId();
4503
4504 Quantum
4505 *magick_restrict pixels;
4506
4507 assert(image != (Image *) NULL);
4508 assert(image->signature == MagickCoreSignature);
4509 assert(image->cache != (Cache) NULL);
4510 cache_info=(CacheInfo *) image->cache;
4511 assert(cache_info->signature == MagickCoreSignature);
4512 if (cache_info->methods.queue_authentic_pixels_handler !=
4513 (QueueAuthenticPixelsHandler) NULL)
4514 {
4515 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4516 columns,rows,exception);
4517 return(pixels);
4518 }
4519 assert(id < (int) cache_info->number_threads);
4520 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4521 cache_info->nexus_info[id],exception);
4522 return(pixels);
4523}
4524␌
4525/*
4526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4527% %
4528% %
4529% %
4530+ 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 %
4531% %
4532% %
4533% %
4534%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4535%
4536% ReadPixelCacheMetacontent() reads metacontent from the specified region of
4537% the pixel cache.
4538%
4539% The format of the ReadPixelCacheMetacontent() method is:
4540%
4541% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4542% NexusInfo *nexus_info,ExceptionInfo *exception)
4543%
4544% A description of each parameter follows:
4545%
4546% o cache_info: the pixel cache.
4547%
4548% o nexus_info: the cache nexus to read the metacontent.
4549%
4550% o exception: return any errors or warnings in this structure.
4551%
4552*/
4553
4554static inline MagickOffsetType ReadPixelCacheRegion(
4555 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4556 const MagickSizeType length,unsigned char *magick_restrict buffer)
4557{
4558 MagickOffsetType
4559 i;
4560
4561 ssize_t
4562 count = 0;
4563
4564 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4565 return((MagickOffsetType) -1);
4566 for (i=0; i < (MagickOffsetType) length; i+=count)
4567 {
4568 count=MagickRead(cache_info->file,buffer+i,(size_t) MagickMin(length-
4569 (MagickSizeType) i,(size_t) MagickMaxBufferExtent));
4570 if (count <= 0)
4571 break;
4572 }
4573 return(i);
4574}
4575
4576static MagickBooleanType ReadPixelCacheMetacontent(
4577 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4578 ExceptionInfo *exception)
4579{
4580 MagickOffsetType
4581 count,
4582 offset;
4583
4584 MagickSizeType
4585 extent,
4586 length;
4587
4588 ssize_t
4589 y;
4590
4591 unsigned char
4592 *magick_restrict q;
4593
4594 size_t
4595 rows;
4596
4597 if (cache_info->metacontent_extent == 0)
4598 return(MagickFalse);
4599 if (nexus_info->authentic_pixel_cache != MagickFalse)
4600 return(MagickTrue);
4601 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
4602 return(MagickFalse);
4603 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
4604 nexus_info->region.x;
4605 length=(MagickSizeType) nexus_info->region.width*
4606 cache_info->metacontent_extent;
4607 extent=length*nexus_info->region.height;
4608 rows=nexus_info->region.height;
4609 y=0;
4610 q=(unsigned char *) nexus_info->metacontent;
4611 switch (cache_info->type)
4612 {
4613 case MemoryCache:
4614 case MapCache:
4615 {
4616 unsigned char
4617 *magick_restrict p;
4618
4619 /*
4620 Read meta-content from memory.
4621 */
4622 if ((cache_info->columns == nexus_info->region.width) &&
4623 (extent == (MagickSizeType) ((size_t) extent)))
4624 {
4625 length=extent;
4626 rows=1UL;
4627 }
4628 p=(unsigned char *) cache_info->metacontent+offset*(MagickOffsetType)
4629 cache_info->metacontent_extent;
4630 for (y=0; y < (ssize_t) rows; y++)
4631 {
4632 (void) memcpy(q,p,(size_t) length);
4633 p+=(ptrdiff_t) (cache_info->metacontent_extent*cache_info->columns);
4634 q+=(ptrdiff_t) (cache_info->metacontent_extent*
4635 nexus_info->region.width);
4636 }
4637 break;
4638 }
4639 case DiskCache:
4640 {
4641 /*
4642 Read meta content from disk.
4643 */
4644 LockSemaphoreInfo(cache_info->file_semaphore);
4645 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4646 {
4647 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4648 cache_info->cache_filename);
4649 UnlockSemaphoreInfo(cache_info->file_semaphore);
4650 return(MagickFalse);
4651 }
4652 if ((cache_info->columns == nexus_info->region.width) &&
4653 (extent <= MagickMaxBufferExtent))
4654 {
4655 length=extent;
4656 rows=1UL;
4657 }
4658 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4659 for (y=0; y < (ssize_t) rows; y++)
4660 {
4661 count=ReadPixelCacheRegion(cache_info,cache_info->offset+
4662 (MagickOffsetType) extent*(MagickOffsetType)
4663 cache_info->number_channels*(MagickOffsetType) sizeof(Quantum)+offset*
4664 (MagickOffsetType) cache_info->metacontent_extent,length,
4665 (unsigned char *) q);
4666 if (count != (MagickOffsetType) length)
4667 break;
4668 offset+=(MagickOffsetType) cache_info->columns;
4669 q+=(ptrdiff_t) (cache_info->metacontent_extent*
4670 nexus_info->region.width);
4671 }
4672 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4673 (void) ClosePixelCacheOnDisk(cache_info);
4674 UnlockSemaphoreInfo(cache_info->file_semaphore);
4675 break;
4676 }
4677 case DistributedCache:
4678 {
4679 RectangleInfo
4680 region;
4681
4682 /*
4683 Read metacontent from distributed cache.
4684 */
4685 LockSemaphoreInfo(cache_info->file_semaphore);
4686 region=nexus_info->region;
4687 if ((cache_info->columns != nexus_info->region.width) ||
4688 (extent > MagickMaxBufferExtent))
4689 region.height=1UL;
4690 else
4691 {
4692 length=extent;
4693 rows=1UL;
4694 }
4695 for (y=0; y < (ssize_t) rows; y++)
4696 {
4697 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4698 cache_info->server_info,&region,length,(unsigned char *) q);
4699 if (count != (MagickOffsetType) length)
4700 break;
4701 q+=(ptrdiff_t) (cache_info->metacontent_extent*
4702 nexus_info->region.width);
4703 region.y++;
4704 }
4705 UnlockSemaphoreInfo(cache_info->file_semaphore);
4706 break;
4707 }
4708 default:
4709 break;
4710 }
4711 if (y < (ssize_t) rows)
4712 {
4713 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4714 cache_info->cache_filename);
4715 return(MagickFalse);
4716 }
4717 if ((cache_info->debug != MagickFalse) &&
4718 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4719 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4720 "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
4721 nexus_info->region.width,(double) nexus_info->region.height,(double)
4722 nexus_info->region.x,(double) nexus_info->region.y);
4723 return(MagickTrue);
4724}
4725␌
4726/*
4727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4728% %
4729% %
4730% %
4731+ R e a d P i x e l C a c h e P i x e l s %
4732% %
4733% %
4734% %
4735%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4736%
4737% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4738% cache.
4739%
4740% The format of the ReadPixelCachePixels() method is:
4741%
4742% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4743% NexusInfo *nexus_info,ExceptionInfo *exception)
4744%
4745% A description of each parameter follows:
4746%
4747% o cache_info: the pixel cache.
4748%
4749% o nexus_info: the cache nexus to read the pixels.
4750%
4751% o exception: return any errors or warnings in this structure.
4752%
4753*/
4754static MagickBooleanType ReadPixelCachePixels(
4755 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4756 ExceptionInfo *exception)
4757{
4758 MagickOffsetType
4759 count,
4760 offset;
4761
4762 MagickSizeType
4763 extent,
4764 length;
4765
4766 Quantum
4767 *magick_restrict q;
4768
4769 size_t
4770 number_channels,
4771 rows;
4772
4773 ssize_t
4774 y;
4775
4776 if (nexus_info->authentic_pixel_cache != MagickFalse)
4777 return(MagickTrue);
4778 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
4779 return(MagickFalse);
4780 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns;
4781 if ((offset/(ssize_t) cache_info->columns) != nexus_info->region.y)
4782 return(MagickFalse);
4783 offset+=nexus_info->region.x;
4784 number_channels=cache_info->number_channels;
4785 length=(MagickSizeType) number_channels*nexus_info->region.width*
4786 sizeof(Quantum);
4787 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4788 return(MagickFalse);
4789 rows=nexus_info->region.height;
4790 extent=length*rows;
4791 if ((extent == 0) || ((extent/length) != rows))
4792 return(MagickFalse);
4793 y=0;
4794 q=nexus_info->pixels;
4795 switch (cache_info->type)
4796 {
4797 case MemoryCache:
4798 case MapCache:
4799 {
4800 Quantum
4801 *magick_restrict p;
4802
4803 /*
4804 Read pixels from memory.
4805 */
4806 if ((cache_info->columns == nexus_info->region.width) &&
4807 (extent == (MagickSizeType) ((size_t) extent)))
4808 {
4809 length=extent;
4810 rows=1UL;
4811 }
4812 p=cache_info->pixels+(MagickOffsetType) cache_info->number_channels*
4813 offset;
4814 for (y=0; y < (ssize_t) rows; y++)
4815 {
4816 (void) memcpy(q,p,(size_t) length);
4817 p+=(ptrdiff_t) (cache_info->number_channels*cache_info->columns);
4818 q+=(ptrdiff_t) (cache_info->number_channels*nexus_info->region.width);
4819 }
4820 break;
4821 }
4822 case DiskCache:
4823 {
4824 /*
4825 Read pixels from disk.
4826 */
4827 LockSemaphoreInfo(cache_info->file_semaphore);
4828 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4829 {
4830 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4831 cache_info->cache_filename);
4832 UnlockSemaphoreInfo(cache_info->file_semaphore);
4833 return(MagickFalse);
4834 }
4835 if ((cache_info->columns == nexus_info->region.width) &&
4836 (extent <= MagickMaxBufferExtent))
4837 {
4838 length=extent;
4839 rows=1UL;
4840 }
4841 for (y=0; y < (ssize_t) rows; y++)
4842 {
4843 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4844 (MagickOffsetType) cache_info->number_channels*(MagickOffsetType)
4845 sizeof(*q),length,(unsigned char *) q);
4846 if (count != (MagickOffsetType) length)
4847 break;
4848 offset+=(MagickOffsetType) cache_info->columns;
4849 q+=(ptrdiff_t) (cache_info->number_channels*nexus_info->region.width);
4850 }
4851 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4852 (void) ClosePixelCacheOnDisk(cache_info);
4853 UnlockSemaphoreInfo(cache_info->file_semaphore);
4854 break;
4855 }
4856 case DistributedCache:
4857 {
4858 RectangleInfo
4859 region;
4860
4861 /*
4862 Read pixels from distributed cache.
4863 */
4864 LockSemaphoreInfo(cache_info->file_semaphore);
4865 region=nexus_info->region;
4866 if ((cache_info->columns != nexus_info->region.width) ||
4867 (extent > MagickMaxBufferExtent))
4868 region.height=1UL;
4869 else
4870 {
4871 length=extent;
4872 rows=1UL;
4873 }
4874 for (y=0; y < (ssize_t) rows; y++)
4875 {
4876 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4877 cache_info->server_info,&region,length,(unsigned char *) q);
4878 if (count != (MagickOffsetType) length)
4879 break;
4880 q+=(ptrdiff_t) (cache_info->number_channels*nexus_info->region.width);
4881 region.y++;
4882 }
4883 UnlockSemaphoreInfo(cache_info->file_semaphore);
4884 break;
4885 }
4886 default:
4887 break;
4888 }
4889 if (y < (ssize_t) rows)
4890 {
4891 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4892 cache_info->cache_filename);
4893 return(MagickFalse);
4894 }
4895 if ((cache_info->debug != MagickFalse) &&
4896 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4897 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4898 "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
4899 nexus_info->region.width,(double) nexus_info->region.height,(double)
4900 nexus_info->region.x,(double) nexus_info->region.y);
4901 return(MagickTrue);
4902}
4903␌
4904/*
4905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4906% %
4907% %
4908% %
4909+ R e f e r e n c e P i x e l C a c h e %
4910% %
4911% %
4912% %
4913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4914%
4915% ReferencePixelCache() increments the reference count associated with the
4916% pixel cache returning a pointer to the cache.
4917%
4918% The format of the ReferencePixelCache method is:
4919%
4920% Cache ReferencePixelCache(Cache cache_info)
4921%
4922% A description of each parameter follows:
4923%
4924% o cache_info: the pixel cache.
4925%
4926*/
4927MagickPrivate Cache ReferencePixelCache(Cache cache)
4928{
4929 CacheInfo
4930 *magick_restrict cache_info;
4931
4932 assert(cache != (Cache *) NULL);
4933 cache_info=(CacheInfo *) cache;
4934 assert(cache_info->signature == MagickCoreSignature);
4935 LockSemaphoreInfo(cache_info->semaphore);
4936 cache_info->reference_count++;
4937 UnlockSemaphoreInfo(cache_info->semaphore);
4938 return(cache_info);
4939}
4940␌
4941/*
4942%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4943% %
4944% %
4945% %
4946+ R e s e t P i x e l C a c h e C h a n n e l s %
4947% %
4948% %
4949% %
4950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4951%
4952% ResetPixelCacheChannels() resets the pixel cache channels.
4953%
4954% The format of the ResetPixelCacheChannels method is:
4955%
4956% void ResetPixelCacheChannels(Image *)
4957%
4958% A description of each parameter follows:
4959%
4960% o image: the image.
4961%
4962*/
4963MagickPrivate void ResetPixelCacheChannels(Image *image)
4964{
4965 CacheInfo
4966 *magick_restrict cache_info;
4967
4968 assert(image != (const Image *) NULL);
4969 assert(image->signature == MagickCoreSignature);
4970 assert(image->cache != (Cache) NULL);
4971 cache_info=(CacheInfo *) image->cache;
4972 assert(cache_info->signature == MagickCoreSignature);
4973 cache_info->number_channels=GetPixelChannels(image);
4974}
4975␌
4976/*
4977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4978% %
4979% %
4980% %
4981+ 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 %
4982% %
4983% %
4984% %
4985%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4986%
4987% ResetCacheAnonymousMemory() resets the anonymous_memory value.
4988%
4989% The format of the ResetCacheAnonymousMemory method is:
4990%
4991% void ResetCacheAnonymousMemory(void)
4992%
4993*/
4994MagickPrivate void ResetCacheAnonymousMemory(void)
4995{
4996 cache_anonymous_memory=0;
4997}
4998␌
4999/*
5000%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5001% %
5002% %
5003% %
5004% R e s h a p e P i x e l C a c h e %
5005% %
5006% %
5007% %
5008%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5009%
5010% ReshapePixelCache() reshapes an existing pixel cache.
5011%
5012% The format of the ReshapePixelCache() method is:
5013%
5014% MagickBooleanType ReshapePixelCache(Image *image,const size_t columns,
5015% const size_t rows,ExceptionInfo *exception)
5016%
5017% A description of each parameter follows:
5018%
5019% o image: the image.
5020%
5021% o columns: the number of columns in the reshaped pixel cache.
5022%
5023% o rows: number of rows in the reshaped pixel cache.
5024%
5025% o exception: return any errors or warnings in this structure.
5026%
5027*/
5028MagickExport MagickBooleanType ReshapePixelCache(Image *image,
5029 const size_t columns,const size_t rows,ExceptionInfo *exception)
5030{
5031 CacheInfo
5032 *cache_info;
5033
5034 MagickSizeType
5035 extent;
5036
5037 assert(image != (Image *) NULL);
5038 assert(image->signature == MagickCoreSignature);
5039 if (IsEventLogging() != MagickFalse)
5040 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5041 assert(image->cache != (void *) NULL);
5042 extent=(MagickSizeType) columns*rows;
5043 if (extent > ((MagickSizeType) image->columns*image->rows))
5044 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
5045 image->filename);
5046 image->columns=columns;
5047 image->rows=rows;
5048 cache_info=(CacheInfo *) image->cache;
5049 cache_info->columns=columns;
5050 cache_info->rows=rows;
5051 return(SyncImagePixelCache(image,exception));
5052}
5053␌
5054/*
5055%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5056% %
5057% %
5058% %
5059+ S e t P i x e l C a c h e M e t h o d s %
5060% %
5061% %
5062% %
5063%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5064%
5065% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
5066%
5067% The format of the SetPixelCacheMethods() method is:
5068%
5069% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
5070%
5071% A description of each parameter follows:
5072%
5073% o cache: the pixel cache.
5074%
5075% o cache_methods: Specifies a pointer to a CacheMethods structure.
5076%
5077*/
5078MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
5079{
5080 CacheInfo
5081 *magick_restrict cache_info;
5082
5083 GetOneAuthenticPixelFromHandler
5084 get_one_authentic_pixel_from_handler;
5085
5086 GetOneVirtualPixelFromHandler
5087 get_one_virtual_pixel_from_handler;
5088
5089 /*
5090 Set cache pixel methods.
5091 */
5092 assert(cache != (Cache) NULL);
5093 assert(cache_methods != (CacheMethods *) NULL);
5094 cache_info=(CacheInfo *) cache;
5095 assert(cache_info->signature == MagickCoreSignature);
5096 if (IsEventLogging() != MagickFalse)
5097 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5098 cache_info->filename);
5099 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
5100 cache_info->methods.get_virtual_pixel_handler=
5101 cache_methods->get_virtual_pixel_handler;
5102 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
5103 cache_info->methods.destroy_pixel_handler=
5104 cache_methods->destroy_pixel_handler;
5105 if (cache_methods->get_virtual_metacontent_from_handler !=
5106 (GetVirtualMetacontentFromHandler) NULL)
5107 cache_info->methods.get_virtual_metacontent_from_handler=
5108 cache_methods->get_virtual_metacontent_from_handler;
5109 if (cache_methods->get_authentic_pixels_handler !=
5110 (GetAuthenticPixelsHandler) NULL)
5111 cache_info->methods.get_authentic_pixels_handler=
5112 cache_methods->get_authentic_pixels_handler;
5113 if (cache_methods->queue_authentic_pixels_handler !=
5114 (QueueAuthenticPixelsHandler) NULL)
5115 cache_info->methods.queue_authentic_pixels_handler=
5116 cache_methods->queue_authentic_pixels_handler;
5117 if (cache_methods->sync_authentic_pixels_handler !=
5118 (SyncAuthenticPixelsHandler) NULL)
5119 cache_info->methods.sync_authentic_pixels_handler=
5120 cache_methods->sync_authentic_pixels_handler;
5121 if (cache_methods->get_authentic_pixels_from_handler !=
5122 (GetAuthenticPixelsFromHandler) NULL)
5123 cache_info->methods.get_authentic_pixels_from_handler=
5124 cache_methods->get_authentic_pixels_from_handler;
5125 if (cache_methods->get_authentic_metacontent_from_handler !=
5126 (GetAuthenticMetacontentFromHandler) NULL)
5127 cache_info->methods.get_authentic_metacontent_from_handler=
5128 cache_methods->get_authentic_metacontent_from_handler;
5129 get_one_virtual_pixel_from_handler=
5130 cache_info->methods.get_one_virtual_pixel_from_handler;
5131 if (get_one_virtual_pixel_from_handler !=
5132 (GetOneVirtualPixelFromHandler) NULL)
5133 cache_info->methods.get_one_virtual_pixel_from_handler=
5134 cache_methods->get_one_virtual_pixel_from_handler;
5135 get_one_authentic_pixel_from_handler=
5136 cache_methods->get_one_authentic_pixel_from_handler;
5137 if (get_one_authentic_pixel_from_handler !=
5138 (GetOneAuthenticPixelFromHandler) NULL)
5139 cache_info->methods.get_one_authentic_pixel_from_handler=
5140 cache_methods->get_one_authentic_pixel_from_handler;
5141}
5142␌
5143/*
5144%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5145% %
5146% %
5147% %
5148+ S e t P i x e l C a c h e N e x u s P i x e l s %
5149% %
5150% %
5151% %
5152%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5153%
5154% SetPixelCacheNexusPixels() defines the region of the cache for the
5155% specified cache nexus.
5156%
5157% The format of the SetPixelCacheNexusPixels() method is:
5158%
5159% Quantum SetPixelCacheNexusPixels(
5160% const CacheInfo *magick_restrict cache_info,const MapMode mode,
5161% const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5162% const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5163% ExceptionInfo *exception)
5164%
5165% A description of each parameter follows:
5166%
5167% o cache_info: the pixel cache.
5168%
5169% o mode: ReadMode, WriteMode, or IOMode.
5170%
5171% o x,y,width,height: define the region of this particular cache nexus.
5172%
5173% o buffered: if true, nexus pixels are buffered.
5174%
5175% o nexus_info: the cache nexus to set.
5176%
5177% o exception: return any errors or warnings in this structure.
5178%
5179*/
5180
5181static inline MagickBooleanType AcquireCacheNexusPixels(
5182 const CacheInfo *magick_restrict cache_info,const MagickSizeType length,
5183 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5184{
5185 if (length != (MagickSizeType) ((size_t) length))
5186 {
5187 (void) ThrowMagickException(exception,GetMagickModule(),
5188 ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
5189 cache_info->filename);
5190 return(MagickFalse);
5191 }
5192 nexus_info->length=0;
5193 nexus_info->mapped=MagickFalse;
5194 if (cache_anonymous_memory <= 0)
5195 {
5196 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
5197 (size_t) length));
5198 if (nexus_info->cache != (Quantum *) NULL)
5199 (void) memset(nexus_info->cache,0,(size_t) length);
5200 }
5201 else
5202 {
5203 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t) length);
5204 if (nexus_info->cache != (Quantum *) NULL)
5205 nexus_info->mapped=MagickTrue;
5206 }
5207 if (nexus_info->cache == (Quantum *) NULL)
5208 {
5209 (void) ThrowMagickException(exception,GetMagickModule(),
5210 ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
5211 cache_info->filename);
5212 return(MagickFalse);
5213 }
5214 nexus_info->length=length;
5215 return(MagickTrue);
5216}
5217
5218static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
5219 const MapMode mode)
5220{
5221 if (nexus_info->length < CACHE_LINE_SIZE)
5222 return;
5223 if (mode == ReadMode)
5224 {
5225 MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,
5226 0,1);
5227 return;
5228 }
5229 MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,1,1);
5230}
5231
5232static Quantum *SetPixelCacheNexusPixels(
5233 const CacheInfo *magick_restrict cache_info,const MapMode mode,
5234 const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5235 const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5236 ExceptionInfo *exception)
5237{
5238 MagickBooleanType
5239 status;
5240
5241 MagickSizeType
5242 length,
5243 number_pixels;
5244
5245 assert(cache_info != (const CacheInfo *) NULL);
5246 assert(cache_info->signature == MagickCoreSignature);
5247 if (cache_info->type == UndefinedCache)
5248 return((Quantum *) NULL);
5249 assert(nexus_info->signature == MagickCoreSignature);
5250 (void) memset(&nexus_info->region,0,sizeof(nexus_info->region));
5251 if ((width == 0) || (height == 0))
5252 {
5253 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
5254 "NoPixelsDefinedInCache","`%s'",cache_info->filename);
5255 return((Quantum *) NULL);
5256 }
5257 if (((MagickSizeType) width > cache_info->width_limit) ||
5258 ((MagickSizeType) height > cache_info->height_limit))
5259 {
5260 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
5261 "WidthOrHeightExceedsLimit","`%s'",cache_info->filename);
5262 return((Quantum *) NULL);
5263 }
5264 if ((IsValidPixelOffset(x,width) == MagickFalse) ||
5265 (IsValidPixelOffset(y,height) == MagickFalse))
5266 {
5267 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
5268 "InvalidPixel","`%s'",cache_info->filename);
5269 return((Quantum *) NULL);
5270 }
5271 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
5272 (buffered == MagickFalse))
5273 {
5274 if (((x >= 0) && (y >= 0) &&
5275 (((ssize_t) height+y-1) < (ssize_t) cache_info->rows)) &&
5276 (((x == 0) && (width == cache_info->columns)) || ((height == 1) &&
5277 (((ssize_t) width+x-1) < (ssize_t) cache_info->columns))))
5278 {
5279 MagickOffsetType
5280 offset;
5281
5282 /*
5283 Pixels are accessed directly from memory.
5284 */
5285 if (IsValidPixelOffset(y,cache_info->columns) == MagickFalse)
5286 return((Quantum *) NULL);
5287 offset=y*(MagickOffsetType) cache_info->columns+x;
5288 nexus_info->pixels=cache_info->pixels+(MagickOffsetType)
5289 cache_info->number_channels*offset;
5290 nexus_info->metacontent=(void *) NULL;
5291 if (cache_info->metacontent_extent != 0)
5292 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5293 offset*(MagickOffsetType) cache_info->metacontent_extent;
5294 nexus_info->region.width=width;
5295 nexus_info->region.height=height;
5296 nexus_info->region.x=x;
5297 nexus_info->region.y=y;
5298 nexus_info->authentic_pixel_cache=MagickTrue;
5299 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5300 return(nexus_info->pixels);
5301 }
5302 }
5303 /*
5304 Pixels are stored in a staging region until they are synced to the cache.
5305 */
5306 if (CacheOverflowSanityCheckGetSize(width,height,&number_pixels) != MagickFalse)
5307 {
5308 (void) ThrowMagickException(exception,GetMagickModule(),
5309 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5310 cache_info->filename);
5311 return((Quantum *) NULL);
5312 }
5313 {
5314 MagickSizeType
5315 extent,
5316 packets;
5317
5318 packets=MagickMax(number_pixels,MagickMax(cache_info->columns,
5319 cache_info->rows));
5320 if ((CacheOverflowSanityCheckGetSize(packets,cache_info->number_channels,&length) != MagickFalse) ||
5321 (CacheOverflowSanityCheckGetSize(length,sizeof(*nexus_info->pixels),&length) != MagickFalse))
5322 {
5323 (void) ThrowMagickException(exception,GetMagickModule(),
5324 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5325 cache_info->filename);
5326 return((Quantum *) NULL);
5327 }
5328 if (cache_info->metacontent_extent != 0)
5329 {
5330 if ((CacheOverflowSanityCheckGetSize(number_pixels,cache_info->metacontent_extent,&extent) != MagickFalse) ||
5331 (extent > (MagickSizeType) (~((MagickSizeType) 0))-length))
5332 {
5333 (void) ThrowMagickException(exception,GetMagickModule(),
5334 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5335 cache_info->filename);
5336 return((Quantum *) NULL);
5337 }
5338 length+=extent;
5339 }
5340 }
5341 status=MagickTrue;
5342 if (nexus_info->cache == (Quantum *) NULL)
5343 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5344 else
5345 if (nexus_info->length < length)
5346 {
5347 RelinquishCacheNexusPixels(nexus_info);
5348 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5349 }
5350 if (status == MagickFalse)
5351 return((Quantum *) NULL);
5352 nexus_info->pixels=nexus_info->cache;
5353 nexus_info->metacontent=(void *) NULL;
5354 if (cache_info->metacontent_extent != 0)
5355 nexus_info->metacontent=(void *) (nexus_info->pixels+
5356 cache_info->number_channels*number_pixels);
5357 nexus_info->region.width=width;
5358 nexus_info->region.height=height;
5359 nexus_info->region.x=x;
5360 nexus_info->region.y=y;
5361 nexus_info->authentic_pixel_cache=cache_info->type == PingCache ?
5362 MagickTrue : MagickFalse;
5363 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5364 return(nexus_info->pixels);
5365}
5366␌
5367/*
5368%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5369% %
5370% %
5371% %
5372% 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 %
5373% %
5374% %
5375% %
5376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5377%
5378% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5379% pixel cache and returns the previous setting. A virtual pixel is any pixel
5380% access that is outside the boundaries of the image cache.
5381%
5382% The format of the SetPixelCacheVirtualMethod() method is:
5383%
5384% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5385% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5386%
5387% A description of each parameter follows:
5388%
5389% o image: the image.
5390%
5391% o virtual_pixel_method: choose the type of virtual pixel.
5392%
5393% o exception: return any errors or warnings in this structure.
5394%
5395*/
5396
5397static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
5398 ExceptionInfo *exception)
5399{
5400 CacheView
5401 *magick_restrict image_view;
5402
5403 MagickBooleanType
5404 status;
5405
5406 ssize_t
5407 y;
5408
5409 assert(image != (Image *) NULL);
5410 assert(image->signature == MagickCoreSignature);
5411 if (IsEventLogging() != MagickFalse)
5412 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5413 assert(image->cache != (Cache) NULL);
5414 image->alpha_trait=BlendPixelTrait;
5415 status=MagickTrue;
5416 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
5417#if defined(MAGICKCORE_OPENMP_SUPPORT)
5418 #pragma omp parallel for schedule(static) shared(status) \
5419 magick_number_threads(image,image,image->rows,2)
5420#endif
5421 for (y=0; y < (ssize_t) image->rows; y++)
5422 {
5423 Quantum
5424 *magick_restrict q;
5425
5426 ssize_t
5427 x;
5428
5429 if (status == MagickFalse)
5430 continue;
5431 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5432 if (q == (Quantum *) NULL)
5433 {
5434 status=MagickFalse;
5435 continue;
5436 }
5437 for (x=0; x < (ssize_t) image->columns; x++)
5438 {
5439 SetPixelAlpha(image,alpha,q);
5440 q+=(ptrdiff_t) GetPixelChannels(image);
5441 }
5442 status=SyncCacheViewAuthenticPixels(image_view,exception);
5443 }
5444 image_view=DestroyCacheView(image_view);
5445 return(status);
5446}
5447
5448MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5449 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5450{
5451 CacheInfo
5452 *magick_restrict cache_info;
5453
5454 VirtualPixelMethod
5455 method;
5456
5457 assert(image != (Image *) NULL);
5458 assert(image->signature == MagickCoreSignature);
5459 if (IsEventLogging() != MagickFalse)
5460 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5461 assert(image->cache != (Cache) NULL);
5462 cache_info=(CacheInfo *) image->cache;
5463 assert(cache_info->signature == MagickCoreSignature);
5464 method=cache_info->virtual_pixel_method;
5465 cache_info->virtual_pixel_method=virtual_pixel_method;
5466 if ((image->columns != 0) && (image->rows != 0))
5467 switch (virtual_pixel_method)
5468 {
5469 case BackgroundVirtualPixelMethod:
5470 {
5471 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
5472 ((image->alpha_trait & BlendPixelTrait) == 0))
5473 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5474 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
5475 (IsGrayColorspace(image->colorspace) != MagickFalse))
5476 (void) SetImageColorspace(image,sRGBColorspace,exception);
5477 break;
5478 }
5479 case TransparentVirtualPixelMethod:
5480 {
5481 if ((image->alpha_trait & BlendPixelTrait) == 0)
5482 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5483 break;
5484 }
5485 default:
5486 break;
5487 }
5488 return(method);
5489}
5490
5491#if defined(MAGICKCORE_OPENCL_SUPPORT)
5492/*
5493%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5494% %
5495% %
5496% %
5497+ 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 %
5498% %
5499% %
5500% %
5501%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5502%
5503% SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
5504% been completed and updates the host memory.
5505%
5506% The format of the SyncAuthenticOpenCLBuffer() method is:
5507%
5508% void SyncAuthenticOpenCLBuffer(const Image *image)
5509%
5510% A description of each parameter follows:
5511%
5512% o image: the image.
5513%
5514*/
5515
5516static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5517{
5518 assert(cache_info != (CacheInfo *) NULL);
5519 assert(cache_info->signature == MagickCoreSignature);
5520 if ((cache_info->type != MemoryCache) ||
5521 (cache_info->opencl == (MagickCLCacheInfo) NULL))
5522 return;
5523 /*
5524 Ensure single threaded access to OpenCL environment.
5525 */
5526 LockSemaphoreInfo(cache_info->semaphore);
5527 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
5528 UnlockSemaphoreInfo(cache_info->semaphore);
5529}
5530
5531MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5532{
5533 CacheInfo
5534 *magick_restrict cache_info;
5535
5536 assert(image != (const Image *) NULL);
5537 cache_info=(CacheInfo *) image->cache;
5538 CopyOpenCLBuffer(cache_info);
5539}
5540#endif
5541␌
5542/*
5543%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5544% %
5545% %
5546% %
5547+ 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 %
5548% %
5549% %
5550% %
5551%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5552%
5553% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5554% in-memory or disk cache. The method returns MagickTrue if the pixel region
5555% is synced, otherwise MagickFalse.
5556%
5557% The format of the SyncAuthenticPixelCacheNexus() method is:
5558%
5559% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5560% NexusInfo *nexus_info,ExceptionInfo *exception)
5561%
5562% A description of each parameter follows:
5563%
5564% o image: the image.
5565%
5566% o nexus_info: the cache nexus to sync.
5567%
5568% o exception: return any errors or warnings in this structure.
5569%
5570*/
5571MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5572 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5573{
5574 CacheInfo
5575 *magick_restrict cache_info;
5576
5577 MagickBooleanType
5578 status;
5579
5580 /*
5581 Transfer pixels to the cache.
5582 */
5583 assert(image != (Image *) NULL);
5584 assert(image->signature == MagickCoreSignature);
5585 if (image->cache == (Cache) NULL)
5586 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5587 cache_info=(CacheInfo *) image->cache;
5588 assert(cache_info->signature == MagickCoreSignature);
5589 if (cache_info->type == UndefinedCache)
5590 return(MagickFalse);
5591 if ((image->mask_trait & UpdatePixelTrait) != 0)
5592 {
5593 if (((image->channels & WriteMaskChannel) != 0) &&
5594 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5595 return(MagickFalse);
5596 if (((image->channels & CompositeMaskChannel) != 0) &&
5597 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5598 return(MagickFalse);
5599 }
5600 if (nexus_info->authentic_pixel_cache != MagickFalse)
5601 {
5602 if (image->taint == MagickFalse)
5603 image->taint=MagickTrue;
5604 return(MagickTrue);
5605 }
5606 assert(cache_info->signature == MagickCoreSignature);
5607 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5608 if ((cache_info->metacontent_extent != 0) &&
5609 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5610 return(MagickFalse);
5611 if ((status != MagickFalse) && (image->taint == MagickFalse))
5612 image->taint=MagickTrue;
5613 return(status);
5614}
5615␌
5616/*
5617%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5618% %
5619% %
5620% %
5621+ S y n c A u t h e n t i c P i x e l C a c h e %
5622% %
5623% %
5624% %
5625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5626%
5627% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5628% or disk cache. The method returns MagickTrue if the pixel region is synced,
5629% otherwise MagickFalse.
5630%
5631% The format of the SyncAuthenticPixelsCache() method is:
5632%
5633% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5634% ExceptionInfo *exception)
5635%
5636% A description of each parameter follows:
5637%
5638% o image: the image.
5639%
5640% o exception: return any errors or warnings in this structure.
5641%
5642*/
5643static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5644 ExceptionInfo *exception)
5645{
5646 CacheInfo
5647 *magick_restrict cache_info;
5648
5649 const int
5650 id = GetOpenMPThreadId();
5651
5652 MagickBooleanType
5653 status;
5654
5655 assert(image != (Image *) NULL);
5656 assert(image->signature == MagickCoreSignature);
5657 assert(image->cache != (Cache) NULL);
5658 cache_info=(CacheInfo *) image->cache;
5659 assert(cache_info->signature == MagickCoreSignature);
5660 assert(id < (int) cache_info->number_threads);
5661 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5662 exception);
5663 return(status);
5664}
5665␌
5666/*
5667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5668% %
5669% %
5670% %
5671% S y n c A u t h e n t i c P i x e l s %
5672% %
5673% %
5674% %
5675%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5676%
5677% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5678% The method returns MagickTrue if the pixel region is flushed, otherwise
5679% MagickFalse.
5680%
5681% The format of the SyncAuthenticPixels() method is:
5682%
5683% MagickBooleanType SyncAuthenticPixels(Image *image,
5684% ExceptionInfo *exception)
5685%
5686% A description of each parameter follows:
5687%
5688% o image: the image.
5689%
5690% o exception: return any errors or warnings in this structure.
5691%
5692*/
5693MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5694 ExceptionInfo *exception)
5695{
5696 CacheInfo
5697 *magick_restrict cache_info;
5698
5699 const int
5700 id = GetOpenMPThreadId();
5701
5702 MagickBooleanType
5703 status;
5704
5705 assert(image != (Image *) NULL);
5706 assert(image->signature == MagickCoreSignature);
5707 assert(image->cache != (Cache) NULL);
5708 cache_info=(CacheInfo *) image->cache;
5709 assert(cache_info->signature == MagickCoreSignature);
5710 if (cache_info->methods.sync_authentic_pixels_handler != (SyncAuthenticPixelsHandler) NULL)
5711 {
5712 status=cache_info->methods.sync_authentic_pixels_handler(image,
5713 exception);
5714 return(status);
5715 }
5716 assert(id < (int) cache_info->number_threads);
5717 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5718 exception);
5719 return(status);
5720}
5721␌
5722/*
5723%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5724% %
5725% %
5726% %
5727+ S y n c I m a g e P i x e l C a c h e %
5728% %
5729% %
5730% %
5731%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5732%
5733% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5734% The method returns MagickTrue if the pixel region is flushed, otherwise
5735% MagickFalse.
5736%
5737% The format of the SyncImagePixelCache() method is:
5738%
5739% MagickBooleanType SyncImagePixelCache(Image *image,
5740% ExceptionInfo *exception)
5741%
5742% A description of each parameter follows:
5743%
5744% o image: the image.
5745%
5746% o exception: return any errors or warnings in this structure.
5747%
5748*/
5749MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5750 ExceptionInfo *exception)
5751{
5752 CacheInfo
5753 *magick_restrict cache_info;
5754
5755 assert(image != (Image *) NULL);
5756 assert(exception != (ExceptionInfo *) NULL);
5757 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5758 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5759}
5760␌
5761/*
5762%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5763% %
5764% %
5765% %
5766+ 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 %
5767% %
5768% %
5769% %
5770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5771%
5772% WritePixelCacheMetacontent() writes the meta-content to the specified region
5773% of the pixel cache.
5774%
5775% The format of the WritePixelCacheMetacontent() method is:
5776%
5777% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5778% NexusInfo *nexus_info,ExceptionInfo *exception)
5779%
5780% A description of each parameter follows:
5781%
5782% o cache_info: the pixel cache.
5783%
5784% o nexus_info: the cache nexus to write the meta-content.
5785%
5786% o exception: return any errors or warnings in this structure.
5787%
5788*/
5789static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5790 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5791{
5792 MagickOffsetType
5793 count,
5794 offset;
5795
5796 MagickSizeType
5797 extent,
5798 length;
5799
5800 const unsigned char
5801 *magick_restrict p;
5802
5803 ssize_t
5804 y;
5805
5806 size_t
5807 rows;
5808
5809 if (cache_info->metacontent_extent == 0)
5810 return(MagickFalse);
5811 if (nexus_info->authentic_pixel_cache != MagickFalse)
5812 return(MagickTrue);
5813 if (nexus_info->metacontent == (unsigned char *) NULL)
5814 return(MagickFalse);
5815 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
5816 return(MagickFalse);
5817 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
5818 nexus_info->region.x;
5819 length=(MagickSizeType) nexus_info->region.width*
5820 cache_info->metacontent_extent;
5821 extent=(MagickSizeType) length*nexus_info->region.height;
5822 rows=nexus_info->region.height;
5823 y=0;
5824 p=(unsigned char *) nexus_info->metacontent;
5825 switch (cache_info->type)
5826 {
5827 case MemoryCache:
5828 case MapCache:
5829 {
5830 unsigned char
5831 *magick_restrict q;
5832
5833 /*
5834 Write associated pixels to memory.
5835 */
5836 if ((cache_info->columns == nexus_info->region.width) &&
5837 (extent == (MagickSizeType) ((size_t) extent)))
5838 {
5839 length=extent;
5840 rows=1UL;
5841 }
5842 q=(unsigned char *) cache_info->metacontent+offset*
5843 (MagickOffsetType) cache_info->metacontent_extent;
5844 for (y=0; y < (ssize_t) rows; y++)
5845 {
5846 (void) memcpy(q,p,(size_t) length);
5847 p+=(ptrdiff_t) (nexus_info->region.width*
5848 cache_info->metacontent_extent);
5849 q+=(ptrdiff_t) (cache_info->columns*cache_info->metacontent_extent);
5850 }
5851 break;
5852 }
5853 case DiskCache:
5854 {
5855 /*
5856 Write associated pixels to disk.
5857 */
5858 LockSemaphoreInfo(cache_info->file_semaphore);
5859 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5860 {
5861 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5862 cache_info->cache_filename);
5863 UnlockSemaphoreInfo(cache_info->file_semaphore);
5864 return(MagickFalse);
5865 }
5866 if ((cache_info->columns == nexus_info->region.width) &&
5867 (extent <= MagickMaxBufferExtent))
5868 {
5869 length=extent;
5870 rows=1UL;
5871 }
5872 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5873 for (y=0; y < (ssize_t) rows; y++)
5874 {
5875 count=WritePixelCacheRegion(cache_info,cache_info->offset+
5876 (MagickOffsetType) extent*(MagickOffsetType)
5877 cache_info->number_channels*(MagickOffsetType) sizeof(Quantum)+offset*
5878 (MagickOffsetType) cache_info->metacontent_extent,length,
5879 (const unsigned char *) p);
5880 if (count != (MagickOffsetType) length)
5881 break;
5882 p+=(ptrdiff_t) (cache_info->metacontent_extent*
5883 nexus_info->region.width);
5884 offset+=(MagickOffsetType) cache_info->columns;
5885 }
5886 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5887 (void) ClosePixelCacheOnDisk(cache_info);
5888 UnlockSemaphoreInfo(cache_info->file_semaphore);
5889 break;
5890 }
5891 case DistributedCache:
5892 {
5893 RectangleInfo
5894 region;
5895
5896 /*
5897 Write metacontent to distributed cache.
5898 */
5899 LockSemaphoreInfo(cache_info->file_semaphore);
5900 region=nexus_info->region;
5901 if ((cache_info->columns != nexus_info->region.width) ||
5902 (extent > MagickMaxBufferExtent))
5903 region.height=1UL;
5904 else
5905 {
5906 length=extent;
5907 rows=1UL;
5908 }
5909 for (y=0; y < (ssize_t) rows; y++)
5910 {
5911 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5912 cache_info->server_info,&region,length,(const unsigned char *) p);
5913 if (count != (MagickOffsetType) length)
5914 break;
5915 p+=(ptrdiff_t) (cache_info->metacontent_extent*
5916 nexus_info->region.width);
5917 region.y++;
5918 }
5919 UnlockSemaphoreInfo(cache_info->file_semaphore);
5920 break;
5921 }
5922 default:
5923 break;
5924 }
5925 if (y < (ssize_t) rows)
5926 {
5927 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5928 cache_info->cache_filename);
5929 return(MagickFalse);
5930 }
5931 if ((cache_info->debug != MagickFalse) &&
5932 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5933 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5934 "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
5935 nexus_info->region.width,(double) nexus_info->region.height,(double)
5936 nexus_info->region.x,(double) nexus_info->region.y);
5937 return(MagickTrue);
5938}
5939␌
5940/*
5941%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5942% %
5943% %
5944% %
5945+ W r i t e C a c h e P i x e l s %
5946% %
5947% %
5948% %
5949%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5950%
5951% WritePixelCachePixels() writes image pixels to the specified region of the
5952% pixel cache.
5953%
5954% The format of the WritePixelCachePixels() method is:
5955%
5956% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5957% NexusInfo *nexus_info,ExceptionInfo *exception)
5958%
5959% A description of each parameter follows:
5960%
5961% o cache_info: the pixel cache.
5962%
5963% o nexus_info: the cache nexus to write the pixels.
5964%
5965% o exception: return any errors or warnings in this structure.
5966%
5967*/
5968static MagickBooleanType WritePixelCachePixels(
5969 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5970 ExceptionInfo *exception)
5971{
5972 MagickOffsetType
5973 count,
5974 offset;
5975
5976 MagickSizeType
5977 extent,
5978 length;
5979
5980 const Quantum
5981 *magick_restrict p;
5982
5983 ssize_t
5984 y;
5985
5986 size_t
5987 rows;
5988
5989 if (nexus_info->authentic_pixel_cache != MagickFalse)
5990 return(MagickTrue);
5991 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
5992 return(MagickFalse);
5993 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
5994 nexus_info->region.x;
5995 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5996 sizeof(Quantum);
5997 extent=length*nexus_info->region.height;
5998 rows=nexus_info->region.height;
5999 y=0;
6000 p=nexus_info->pixels;
6001 switch (cache_info->type)
6002 {
6003 case MemoryCache:
6004 case MapCache:
6005 {
6006 Quantum
6007 *magick_restrict q;
6008
6009 /*
6010 Write pixels to memory.
6011 */
6012 if ((cache_info->columns == nexus_info->region.width) &&
6013 (extent == (MagickSizeType) ((size_t) extent)))
6014 {
6015 length=extent;
6016 rows=1UL;
6017 }
6018 q=cache_info->pixels+(MagickOffsetType) cache_info->number_channels*
6019 offset;
6020 for (y=0; y < (ssize_t) rows; y++)
6021 {
6022 (void) memcpy(q,p,(size_t) length);
6023 p+=(ptrdiff_t) (cache_info->number_channels*nexus_info->region.width);
6024 q+=(ptrdiff_t) (cache_info->number_channels*cache_info->columns);
6025 }
6026 break;
6027 }
6028 case DiskCache:
6029 {
6030 /*
6031 Write pixels to disk.
6032 */
6033 LockSemaphoreInfo(cache_info->file_semaphore);
6034 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
6035 {
6036 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
6037 cache_info->cache_filename);
6038 UnlockSemaphoreInfo(cache_info->file_semaphore);
6039 return(MagickFalse);
6040 }
6041 if ((cache_info->columns == nexus_info->region.width) &&
6042 (extent <= MagickMaxBufferExtent))
6043 {
6044 length=extent;
6045 rows=1UL;
6046 }
6047 for (y=0; y < (ssize_t) rows; y++)
6048 {
6049 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
6050 (MagickOffsetType) cache_info->number_channels*(MagickOffsetType)
6051 sizeof(*p),length,(const unsigned char *) p);
6052 if (count != (MagickOffsetType) length)
6053 break;
6054 p+=(ptrdiff_t) (cache_info->number_channels*nexus_info->region.width);
6055 offset+=(MagickOffsetType) cache_info->columns;
6056 }
6057 if (IsFileDescriptorLimitExceeded() != MagickFalse)
6058 (void) ClosePixelCacheOnDisk(cache_info);
6059 UnlockSemaphoreInfo(cache_info->file_semaphore);
6060 break;
6061 }
6062 case DistributedCache:
6063 {
6064 RectangleInfo
6065 region;
6066
6067 /*
6068 Write pixels to distributed cache.
6069 */
6070 LockSemaphoreInfo(cache_info->file_semaphore);
6071 region=nexus_info->region;
6072 if ((cache_info->columns != nexus_info->region.width) ||
6073 (extent > MagickMaxBufferExtent))
6074 region.height=1UL;
6075 else
6076 {
6077 length=extent;
6078 rows=1UL;
6079 }
6080 for (y=0; y < (ssize_t) rows; y++)
6081 {
6082 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
6083 cache_info->server_info,&region,length,(const unsigned char *) p);
6084 if (count != (MagickOffsetType) length)
6085 break;
6086 p+=(ptrdiff_t) (cache_info->number_channels*nexus_info->region.width);
6087 region.y++;
6088 }
6089 UnlockSemaphoreInfo(cache_info->file_semaphore);
6090 break;
6091 }
6092 default:
6093 break;
6094 }
6095 if (y < (ssize_t) rows)
6096 {
6097 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
6098 cache_info->cache_filename);
6099 return(MagickFalse);
6100 }
6101 if ((cache_info->debug != MagickFalse) &&
6102 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
6103 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
6104 "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
6105 nexus_info->region.width,(double) nexus_info->region.height,(double)
6106 nexus_info->region.x,(double) nexus_info->region.y);
6107 return(MagickTrue);
6108}