MagickCore 7.1.2-31
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-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 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2799}
2800
2801static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2802{
2803 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2804}
2805
2806static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2807 const size_t extent)
2808{
2809 MagickModulo
2810 modulo;
2811
2812 modulo.quotient=offset;
2813 modulo.remainder=0;
2814 if (extent != 0)
2815 {
2816 modulo.quotient=offset/((ssize_t) extent);
2817 modulo.remainder=offset % ((ssize_t) extent);
2818 }
2819 if ((modulo.remainder != 0) && ((offset ^ ((ssize_t) extent)) < 0))
2820 {
2821 modulo.quotient-=1;
2822 modulo.remainder+=((ssize_t) extent);
2823 }
2824 return(modulo);
2825}
2826
2827MagickPrivate const Quantum *GetVirtualPixelCacheNexus(const Image *image,
2828 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2829 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2830 ExceptionInfo *exception)
2831{
2832 CacheInfo
2833 *magick_restrict cache_info;
2834
2835 const Quantum
2836 *magick_restrict p;
2837
2838 const void
2839 *magick_restrict r;
2840
2841 MagickOffsetType
2842 offset;
2843
2844 MagickSizeType
2845 length,
2846 number_pixels;
2847
2848 NexusInfo
2849 *magick_restrict virtual_nexus;
2850
2851 Quantum
2852 *magick_restrict pixels,
2853 *magick_restrict q,
2854 virtual_pixel[MaxPixelChannels];
2855
2856 ssize_t
2857 i,
2858 u,
2859 v;
2860
2861 unsigned char
2862 *magick_restrict s;
2863
2864 void
2865 *magick_restrict virtual_metacontent;
2866
2867 /*
2868 Acquire pixels.
2869 */
2870 assert(image != (const Image *) NULL);
2871 assert(image->signature == MagickCoreSignature);
2872 assert(image->cache != (Cache) NULL);
2873 cache_info=(CacheInfo *) image->cache;
2874 assert(cache_info->signature == MagickCoreSignature);
2875 if (cache_info->type == UndefinedCache)
2876 return((const Quantum *) NULL);
2877#if defined(MAGICKCORE_OPENCL_SUPPORT)
2878 CopyOpenCLBuffer(cache_info);
2879#endif
2880 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,x,y,columns,rows,
2881 ((image->channels & WriteMaskChannel) != 0) ||
2882 ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
2883 nexus_info,exception);
2884 if (pixels == (Quantum *) NULL)
2885 return((const Quantum *) NULL);
2886 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
2887 return((const Quantum *) NULL);
2888 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns;
2889 if (IsOffsetOverflow(offset,(MagickOffsetType) nexus_info->region.x) == MagickFalse)
2890 return((const Quantum *) NULL);
2891 offset+=nexus_info->region.x;
2892 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2893 nexus_info->region.width-1L;
2894 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2895 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2896 if ((x >= 0) && ((x+(ssize_t) columns-1) < (ssize_t) cache_info->columns) &&
2897 (y >= 0) && ((y+(ssize_t) rows-1) < (ssize_t) cache_info->rows))
2898 {
2899 MagickBooleanType
2900 status;
2901
2902 /*
2903 Pixel request is inside cache extents.
2904 */
2905 if (nexus_info->authentic_pixel_cache != MagickFalse)
2906 return(pixels);
2907 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2908 if (status == MagickFalse)
2909 return((const Quantum *) NULL);
2910 if (cache_info->metacontent_extent != 0)
2911 {
2912 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2913 if (status == MagickFalse)
2914 return((const Quantum *) NULL);
2915 }
2916 return(pixels);
2917 }
2918 /*
2919 Pixel request is outside cache extents.
2920 */
2921 virtual_nexus=nexus_info->virtual_nexus;
2922 q=pixels;
2923 s=(unsigned char *) nexus_info->metacontent;
2924 (void) memset(virtual_pixel,0,cache_info->number_channels*
2925 sizeof(*virtual_pixel));
2926 virtual_metacontent=(void *) NULL;
2927 switch (virtual_pixel_method)
2928 {
2929 case BackgroundVirtualPixelMethod:
2930 case BlackVirtualPixelMethod:
2931 case GrayVirtualPixelMethod:
2932 case TransparentVirtualPixelMethod:
2933 case MaskVirtualPixelMethod:
2934 case WhiteVirtualPixelMethod:
2935 case EdgeVirtualPixelMethod:
2936 case CheckerTileVirtualPixelMethod:
2937 case HorizontalTileVirtualPixelMethod:
2938 case VerticalTileVirtualPixelMethod:
2939 {
2940 if (cache_info->metacontent_extent != 0)
2941 {
2942 /*
2943 Acquire a metacontent buffer.
2944 */
2945 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2946 cache_info->metacontent_extent);
2947 if (virtual_metacontent == (void *) NULL)
2948 {
2949 (void) ThrowMagickException(exception,GetMagickModule(),
2950 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2951 return((const Quantum *) NULL);
2952 }
2953 (void) memset(virtual_metacontent,0,cache_info->metacontent_extent);
2954 }
2955 switch (virtual_pixel_method)
2956 {
2957 case BlackVirtualPixelMethod:
2958 {
2959 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2960 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2961 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2962 break;
2963 }
2964 case GrayVirtualPixelMethod:
2965 {
2966 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2967 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2968 virtual_pixel);
2969 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2970 break;
2971 }
2972 case TransparentVirtualPixelMethod:
2973 {
2974 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2975 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2976 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2977 break;
2978 }
2979 case MaskVirtualPixelMethod:
2980 case WhiteVirtualPixelMethod:
2981 {
2982 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2983 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2984 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2985 break;
2986 }
2987 default:
2988 {
2989 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2990 virtual_pixel);
2991 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2992 virtual_pixel);
2993 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2994 virtual_pixel);
2995 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2996 virtual_pixel);
2997 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2998 virtual_pixel);
2999 break;
3000 }
3001 }
3002 break;
3003 }
3004 default:
3005 break;
3006 }
3007 for (v=0; v < (ssize_t) rows; v++)
3008 {
3009 ssize_t
3010 y_offset;
3011
3012 y_offset=y+v;
3013 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
3014 (virtual_pixel_method == UndefinedVirtualPixelMethod))
3015 y_offset=EdgeY(y_offset,cache_info->rows);
3016 for (u=0; u < (ssize_t) columns; u+=(ssize_t) length)
3017 {
3018 ssize_t
3019 x_offset;
3020
3021 x_offset=x+u;
3022 length=(MagickSizeType) MagickMin((ssize_t) cache_info->columns-
3023 x_offset,(ssize_t) columns-u);
3024 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
3025 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
3026 (length == 0))
3027 {
3028 MagickModulo
3029 x_modulo,
3030 y_modulo;
3031
3032 /*
3033 Transfer a single pixel.
3034 */
3035 length=(MagickSizeType) 1;
3036 switch (virtual_pixel_method)
3037 {
3038 case EdgeVirtualPixelMethod:
3039 default:
3040 {
3041 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3042 EdgeX(x_offset,cache_info->columns),
3043 EdgeY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
3044 exception);
3045 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3046 break;
3047 }
3048 case RandomVirtualPixelMethod:
3049 {
3050 if (cache_info->random_info == (RandomInfo *) NULL)
3051 cache_info->random_info=AcquireRandomInfo();
3052 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3053 RandomX(cache_info->random_info,cache_info->columns),
3054 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3055 virtual_nexus,exception);
3056 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3057 break;
3058 }
3059 case DitherVirtualPixelMethod:
3060 {
3061 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3062 DitherX(x_offset,cache_info->columns),
3063 DitherY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
3064 exception);
3065 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3066 break;
3067 }
3068 case TileVirtualPixelMethod:
3069 {
3070 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3071 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3072 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3073 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3074 exception);
3075 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3076 break;
3077 }
3078 case MirrorVirtualPixelMethod:
3079 {
3080 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3081 if ((x_modulo.quotient & 0x01) == 1L)
3082 x_modulo.remainder=(ssize_t) cache_info->columns-
3083 x_modulo.remainder-1L;
3084 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3085 if ((y_modulo.quotient & 0x01) == 1L)
3086 y_modulo.remainder=(ssize_t) cache_info->rows-
3087 y_modulo.remainder-1L;
3088 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3089 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3090 exception);
3091 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3092 break;
3093 }
3094 case HorizontalTileEdgeVirtualPixelMethod:
3095 {
3096 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3097 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3098 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
3099 virtual_nexus,exception);
3100 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3101 break;
3102 }
3103 case VerticalTileEdgeVirtualPixelMethod:
3104 {
3105 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3106 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3107 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
3108 virtual_nexus,exception);
3109 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3110 break;
3111 }
3112 case BackgroundVirtualPixelMethod:
3113 case BlackVirtualPixelMethod:
3114 case GrayVirtualPixelMethod:
3115 case TransparentVirtualPixelMethod:
3116 case MaskVirtualPixelMethod:
3117 case WhiteVirtualPixelMethod:
3118 {
3119 p=virtual_pixel;
3120 r=virtual_metacontent;
3121 break;
3122 }
3123 case CheckerTileVirtualPixelMethod:
3124 {
3125 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3126 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3127 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3128 {
3129 p=virtual_pixel;
3130 r=virtual_metacontent;
3131 break;
3132 }
3133 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3134 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3135 exception);
3136 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3137 break;
3138 }
3139 case HorizontalTileVirtualPixelMethod:
3140 {
3141 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
3142 {
3143 p=virtual_pixel;
3144 r=virtual_metacontent;
3145 break;
3146 }
3147 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3148 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3149 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3150 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3151 exception);
3152 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3153 break;
3154 }
3155 case VerticalTileVirtualPixelMethod:
3156 {
3157 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
3158 {
3159 p=virtual_pixel;
3160 r=virtual_metacontent;
3161 break;
3162 }
3163 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3164 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3165 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3166 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3167 exception);
3168 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3169 break;
3170 }
3171 }
3172 if (p == (const Quantum *) NULL)
3173 break;
3174 (void) memcpy(q,p,(size_t) (cache_info->number_channels*length*
3175 sizeof(*p)));
3176 q+=(ptrdiff_t) cache_info->number_channels;
3177 if ((s != (void *) NULL) && (r != (const void *) NULL))
3178 {
3179 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3180 s+=(ptrdiff_t) cache_info->metacontent_extent;
3181 }
3182 continue;
3183 }
3184 /*
3185 Transfer a run of pixels.
3186 */
3187 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x_offset,y_offset,
3188 (size_t) length,1UL,virtual_nexus,exception);
3189 if (p == (const Quantum *) NULL)
3190 break;
3191 r=GetVirtualMetacontentFromNexus(cache_info,virtual_nexus);
3192 (void) memcpy(q,p,(size_t) (cache_info->number_channels*length*
3193 sizeof(*p)));
3194 q+=(ptrdiff_t) cache_info->number_channels*length;
3195 if ((r != (void *) NULL) && (s != (const void *) NULL))
3196 {
3197 (void) memcpy(s,r,(size_t) length);
3198 s+=(ptrdiff_t) length*cache_info->metacontent_extent;
3199 }
3200 }
3201 if (u < (ssize_t) columns)
3202 break;
3203 }
3204 /*
3205 Free resources.
3206 */
3207 if (virtual_metacontent != (void *) NULL)
3208 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3209 if (v < (ssize_t) rows)
3210 return((const Quantum *) NULL);
3211 return(pixels);
3212}
3213
3214/*
3215%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3216% %
3217% %
3218% %
3219+ G e t V i r t u a l P i x e l C a c h e %
3220% %
3221% %
3222% %
3223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3224%
3225% GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3226% cache as defined by the geometry parameters. A pointer to the pixels
3227% is returned if the pixels are transferred, otherwise a NULL is returned.
3228%
3229% The format of the GetVirtualPixelCache() method is:
3230%
3231% const Quantum *GetVirtualPixelCache(const Image *image,
3232% const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3233% const ssize_t y,const size_t columns,const size_t rows,
3234% ExceptionInfo *exception)
3235%
3236% A description of each parameter follows:
3237%
3238% o image: the image.
3239%
3240% o virtual_pixel_method: the virtual pixel method.
3241%
3242% o x,y,columns,rows: These values define the perimeter of a region of
3243% pixels.
3244%
3245% o exception: return any errors or warnings in this structure.
3246%
3247*/
3248static const Quantum *GetVirtualPixelCache(const Image *image,
3249 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3250 const size_t columns,const size_t rows,ExceptionInfo *exception)
3251{
3252 CacheInfo
3253 *magick_restrict cache_info;
3254
3255 const int
3256 id = GetOpenMPThreadId();
3257
3258 const Quantum
3259 *magick_restrict p;
3260
3261 assert(image != (const Image *) NULL);
3262 assert(image->signature == MagickCoreSignature);
3263 assert(image->cache != (Cache) NULL);
3264 cache_info=(CacheInfo *) image->cache;
3265 assert(cache_info->signature == MagickCoreSignature);
3266 assert(id < (int) cache_info->number_threads);
3267 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,columns,rows,
3268 cache_info->nexus_info[id],exception);
3269 return(p);
3270}
3271
3272/*
3273%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3274% %
3275% %
3276% %
3277% G e t V i r t u a l P i x e l Q u e u e %
3278% %
3279% %
3280% %
3281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3282%
3283% GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3284% with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3285%
3286% The format of the GetVirtualPixelQueue() method is:
3287%
3288% const Quantum *GetVirtualPixelQueue(const Image image)
3289%
3290% A description of each parameter follows:
3291%
3292% o image: the image.
3293%
3294*/
3295MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3296{
3297 CacheInfo
3298 *magick_restrict cache_info;
3299
3300 const int
3301 id = GetOpenMPThreadId();
3302
3303 assert(image != (const Image *) NULL);
3304 assert(image->signature == MagickCoreSignature);
3305 assert(image->cache != (Cache) NULL);
3306 cache_info=(CacheInfo *) image->cache;
3307 assert(cache_info->signature == MagickCoreSignature);
3308 if (cache_info->methods.get_virtual_pixels_handler != (GetVirtualPixelsHandler) NULL)
3309 return(cache_info->methods.get_virtual_pixels_handler(image));
3310 assert(id < (int) cache_info->number_threads);
3311 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3312}
3313
3314/*
3315%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3316% %
3317% %
3318% %
3319% G e t V i r t u a l P i x e l s %
3320% %
3321% %
3322% %
3323%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3324%
3325% GetVirtualPixels() returns an immutable pixel region. If the
3326% region is successfully accessed, a pointer to it is returned, otherwise
3327% NULL is returned. The returned pointer may point to a temporary working
3328% copy of the pixels or it may point to the original pixels in memory.
3329% Performance is maximized if the selected region is part of one row, or one
3330% or more full rows, since there is opportunity to access the pixels in-place
3331% (without a copy) if the image is in memory, or in a memory-mapped file. The
3332% returned pointer must *never* be deallocated by the user.
3333%
3334% Pixels accessed via the returned pointer represent a simple array of type
3335% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3336% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3337% access the meta-content (of type void) corresponding to the
3338% region.
3339%
3340% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3341%
3342% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3343% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3344% GetCacheViewAuthenticPixels() instead.
3345%
3346% The format of the GetVirtualPixels() method is:
3347%
3348% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3349% const ssize_t y,const size_t columns,const size_t rows,
3350% ExceptionInfo *exception)
3351%
3352% A description of each parameter follows:
3353%
3354% o image: the image.
3355%
3356% o x,y,columns,rows: These values define the perimeter of a region of
3357% pixels.
3358%
3359% o exception: return any errors or warnings in this structure.
3360%
3361*/
3362MagickExport const Quantum *GetVirtualPixels(const Image *image,
3363 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3364 ExceptionInfo *exception)
3365{
3366 CacheInfo
3367 *magick_restrict cache_info;
3368
3369 const int
3370 id = GetOpenMPThreadId();
3371
3372 const Quantum
3373 *magick_restrict p;
3374
3375 assert(image != (const Image *) NULL);
3376 assert(image->signature == MagickCoreSignature);
3377 assert(image->cache != (Cache) NULL);
3378 cache_info=(CacheInfo *) image->cache;
3379 assert(cache_info->signature == MagickCoreSignature);
3380 if (cache_info->methods.get_virtual_pixel_handler !=
3381 (GetVirtualPixelHandler) NULL)
3382 return(cache_info->methods.get_virtual_pixel_handler(image,
3383 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3384 assert(id < (int) cache_info->number_threads);
3385 p=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3386 columns,rows,cache_info->nexus_info[id],exception);
3387 return(p);
3388}
3389
3390/*
3391%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3392% %
3393% %
3394% %
3395+ 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 %
3396% %
3397% %
3398% %
3399%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3400%
3401% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3402% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3403%
3404% The format of the GetVirtualPixelsCache() method is:
3405%
3406% Quantum *GetVirtualPixelsCache(const Image *image)
3407%
3408% A description of each parameter follows:
3409%
3410% o image: the image.
3411%
3412*/
3413static const Quantum *GetVirtualPixelsCache(const Image *image)
3414{
3415 CacheInfo
3416 *magick_restrict cache_info;
3417
3418 const int
3419 id = GetOpenMPThreadId();
3420
3421 assert(image != (const Image *) NULL);
3422 assert(image->signature == MagickCoreSignature);
3423 assert(image->cache != (Cache) NULL);
3424 cache_info=(CacheInfo *) image->cache;
3425 assert(cache_info->signature == MagickCoreSignature);
3426 assert(id < (int) cache_info->number_threads);
3427 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3428}
3429
3430/*
3431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3432% %
3433% %
3434% %
3435+ G e t V i r t u a l P i x e l s N e x u s %
3436% %
3437% %
3438% %
3439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3440%
3441% GetVirtualPixelsNexus() returns the pixels associated with the specified
3442% cache nexus.
3443%
3444% The format of the GetVirtualPixelsNexus() method is:
3445%
3446% const Quantum *GetVirtualPixelsNexus(const Cache cache,
3447% NexusInfo *nexus_info)
3448%
3449% A description of each parameter follows:
3450%
3451% o cache: the pixel cache.
3452%
3453% o nexus_info: the cache nexus to return the colormap pixels.
3454%
3455*/
3456MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3457 NexusInfo *magick_restrict nexus_info)
3458{
3459 CacheInfo
3460 *magick_restrict cache_info;
3461
3462 assert(cache != (Cache) NULL);
3463 cache_info=(CacheInfo *) cache;
3464 assert(cache_info->signature == MagickCoreSignature);
3465 if (cache_info->storage_class == UndefinedClass)
3466 return((Quantum *) NULL);
3467 return((const Quantum *) nexus_info->pixels);
3468}
3469
3470/*
3471%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3472% %
3473% %
3474% %
3475+ M a s k P i x e l C a c h e N e x u s %
3476% %
3477% %
3478% %
3479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3480%
3481% MaskPixelCacheNexus() masks the cache nexus as defined by the composite mask.
3482% The method returns MagickTrue if the pixel region is masked, otherwise
3483% MagickFalse.
3484%
3485% The format of the MaskPixelCacheNexus() method is:
3486%
3487% MagickBooleanType MaskPixelCacheNexus(Image *image,
3488% NexusInfo *nexus_info,ExceptionInfo *exception)
3489%
3490% A description of each parameter follows:
3491%
3492% o image: the image.
3493%
3494% o nexus_info: the cache nexus to clip.
3495%
3496% o exception: return any errors or warnings in this structure.
3497%
3498*/
3499
3500static inline Quantum ApplyPixelCompositeMask(const Quantum p,
3501 const MagickRealType alpha,const Quantum q,const MagickRealType beta)
3502{
3503 double
3504 gamma;
3505
3506 if (fabs((double) (alpha-(double) TransparentAlpha)) < MagickEpsilon)
3507 return(q);
3508 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3509 gamma=MagickSafeReciprocal(gamma);
3510 return(ClampToQuantum(gamma*MagickOver_((double) p,alpha,(double) q,beta)));
3511}
3512
3513static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3514 ExceptionInfo *exception)
3515{
3516 CacheInfo
3517 *magick_restrict cache_info;
3518
3519 Quantum
3520 *magick_restrict p,
3521 *magick_restrict q;
3522
3523 ssize_t
3524 y;
3525
3526 /*
3527 Apply composite mask.
3528 */
3529 if (IsEventLogging() != MagickFalse)
3530 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3531 if ((image->channels & CompositeMaskChannel) == 0)
3532 return(MagickTrue);
3533 if ((nexus_info->region.width == 0) || (nexus_info->region.height == 0))
3534 return(MagickTrue);
3535 cache_info=(CacheInfo *) image->cache;
3536 if (cache_info == (Cache) NULL)
3537 return(MagickFalse);
3538 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3539 nexus_info->region.width,nexus_info->region.height,
3540 nexus_info->virtual_nexus,exception);
3541 q=nexus_info->pixels;
3542 if ((p == (Quantum *) NULL) || (q == (Quantum *) NULL))
3543 return(MagickFalse);
3544 for (y=0; y < (ssize_t) nexus_info->region.height; y++)
3545 {
3546 ssize_t
3547 x;
3548
3549 for (x=0; x < (ssize_t) nexus_info->region.width; x++)
3550 {
3551 double
3552 alpha;
3553
3554 ssize_t
3555 i;
3556
3557 alpha=(double) GetPixelCompositeMask(image,p);
3558 for (i=0; i < (ssize_t) image->number_channels; i++)
3559 {
3560 PixelChannel channel = GetPixelChannelChannel(image,i);
3561 PixelTrait traits = GetPixelChannelTraits(image,channel);
3562 if ((traits & UpdatePixelTrait) == 0)
3563 continue;
3564 q[i]=ApplyPixelCompositeMask(q[i],alpha,p[i],GetPixelAlpha(image,p));
3565 }
3566 p+=(ptrdiff_t) GetPixelChannels(image);
3567 q+=(ptrdiff_t) GetPixelChannels(image);
3568 }
3569 }
3570 return(MagickTrue);
3571}
3572
3573/*
3574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3575% %
3576% %
3577% %
3578+ O p e n P i x e l C a c h e %
3579% %
3580% %
3581% %
3582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3583%
3584% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3585% dimensions, allocating space for the image pixels and optionally the
3586% metacontent, and memory mapping the cache if it is disk based. The cache
3587% nexus array is initialized as well.
3588%
3589% The format of the OpenPixelCache() method is:
3590%
3591% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3592% ExceptionInfo *exception)
3593%
3594% A description of each parameter follows:
3595%
3596% o image: the image.
3597%
3598% o mode: ReadMode, WriteMode, or IOMode.
3599%
3600% o exception: return any errors or warnings in this structure.
3601%
3602*/
3603
3604static inline MagickBooleanType CacheOverflowSanityCheckGetSize(
3605 const MagickSizeType count,const size_t quantum,MagickSizeType *const extent)
3606{
3607 MagickSizeType
3608 length;
3609
3610 if ((count == 0) || (quantum == 0))
3611 return(MagickTrue);
3612 length=count*quantum;
3613 if (quantum != (length/count))
3614 {
3615 errno=ENOMEM;
3616 return(MagickTrue);
3617 }
3618 if (extent != NULL)
3619 *extent=length;
3620 return(MagickFalse);
3621}
3622
3623static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3624 const MapMode mode)
3625{
3626 int
3627 file;
3628
3629 /*
3630 Open pixel cache on disk.
3631 */
3632 if ((cache_info->file != -1) && (cache_info->disk_mode == mode))
3633 return(MagickTrue); /* cache already open and in the proper mode */
3634 if (*cache_info->cache_filename == '\0')
3635 file=AcquireUniqueFileResource(cache_info->cache_filename);
3636 else
3637 switch (mode)
3638 {
3639 case ReadMode:
3640 {
3641 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3642 break;
3643 }
3644 case WriteMode:
3645 {
3646 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3647 O_BINARY | O_EXCL,S_MODE);
3648 if (file == -1)
3649 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3650 break;
3651 }
3652 case IOMode:
3653 default:
3654 {
3655 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3656 O_EXCL,S_MODE);
3657 if (file == -1)
3658 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3659 break;
3660 }
3661 }
3662 if (file == -1)
3663 return(MagickFalse);
3664 (void) AcquireMagickResource(FileResource,1);
3665 if (cache_info->file != -1)
3666 (void) ClosePixelCacheOnDisk(cache_info);
3667 cache_info->file=file;
3668 cache_info->disk_mode=mode;
3669 return(MagickTrue);
3670}
3671
3672static inline MagickOffsetType WritePixelCacheRegion(
3673 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3674 const MagickSizeType length,const unsigned char *magick_restrict buffer)
3675{
3676 MagickOffsetType
3677 i;
3678
3679 ssize_t
3680 count = 0;
3681
3682 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3683 return((MagickOffsetType) -1);
3684 for (i=0; i < (MagickOffsetType) length; i+=count)
3685 {
3686 count=MagickWrite(cache_info->file,buffer+i,(size_t) MagickMin(length-
3687 (MagickSizeType) i,MagickMaxBufferExtent));
3688 if (count <= 0)
3689 break;
3690 }
3691 return(i);
3692}
3693
3694static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3695{
3696 CacheInfo
3697 *magick_restrict cache_info;
3698
3699 MagickOffsetType
3700 offset;
3701
3702 cache_info=(CacheInfo *) image->cache;
3703 if (cache_info->debug != MagickFalse)
3704 {
3705 char
3706 format[MagickPathExtent],
3707 message[MagickPathExtent];
3708
3709 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3710 (void) FormatLocaleString(message,MagickPathExtent,
3711 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3712 cache_info->cache_filename,cache_info->file,format);
3713 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3714 }
3715 if (length != (MagickSizeType) ((MagickOffsetType) length))
3716 return(MagickFalse);
3717 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3718 if (offset < 0)
3719 return(MagickFalse);
3720 if ((MagickSizeType) offset < length)
3721 {
3722 MagickOffsetType
3723 count,
3724 extent;
3725
3726 extent=(MagickOffsetType) length-1;
3727 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3728 "");
3729 if (count != 1)
3730 return(MagickFalse);
3731#if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3732 if (cache_info->synchronize != MagickFalse)
3733 if (posix_fallocate(cache_info->file,offset+1,extent-offset) != 0)
3734 return(MagickFalse);
3735#endif
3736 }
3737 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3738 if (offset < 0)
3739 return(MagickFalse);
3740 return(MagickTrue);
3741}
3742
3743static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3744 ExceptionInfo *exception)
3745{
3746 CacheInfo
3747 *magick_restrict cache_info,
3748 source_info;
3749
3750 char
3751 format[MagickPathExtent],
3752 message[MagickPathExtent];
3753
3754 const char
3755 *hosts,
3756 *type;
3757
3758 MagickBooleanType
3759 status;
3760
3761 MagickSizeType
3762 length = 0,
3763 number_pixels;
3764
3765 size_t
3766 columns,
3767 packet_size;
3768
3769 assert(image != (const Image *) NULL);
3770 assert(image->signature == MagickCoreSignature);
3771 assert(image->cache != (Cache) NULL);
3772 if (IsEventLogging() != MagickFalse)
3773 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3774 if (cache_anonymous_memory < 0)
3775 {
3776 char
3777 *value;
3778
3779 /*
3780 Does the security policy require anonymous mapping for pixel cache?
3781 */
3782 cache_anonymous_memory=0;
3783 value=GetPolicyValue("pixel-cache-memory");
3784 if (value == (char *) NULL)
3785 value=GetPolicyValue("cache:memory-map");
3786 if (LocaleCompare(value,"anonymous") == 0)
3787 {
3788#if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3789 cache_anonymous_memory=1;
3790#else
3791 (void) ThrowMagickException(exception,GetMagickModule(),
3792 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3793 "`%s' (policy requires anonymous memory mapping)",image->filename);
3794#endif
3795 }
3796 value=DestroyString(value);
3797 }
3798 if ((image->columns == 0) || (image->rows == 0))
3799 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3800 cache_info=(CacheInfo *) image->cache;
3801 assert(cache_info->signature == MagickCoreSignature);
3802 if (((MagickSizeType) image->columns > cache_info->width_limit) ||
3803 ((MagickSizeType) image->rows > cache_info->height_limit))
3804 {
3805 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
3806 "WidthOrHeightExceedsLimit","`%s' (%.17gx%.17g) > (%.17gx%.17g)",
3807 image->filename, (double) image->columns, (double) image->rows,
3808 (double) cache_info->width_limit,(double) cache_info->height_limit);
3809 return(MagickFalse);
3810 }
3811 if (GetMagickResourceLimit(ListLengthResource) != MagickResourceInfinity)
3812 {
3813 length=GetImageListLength(image);
3814 if (AcquireMagickResource(ListLengthResource,length) == MagickFalse)
3815 ThrowBinaryException(ResourceLimitError,"ListLengthExceedsLimit",
3816 image->filename);
3817 }
3818 source_info=(*cache_info);
3819 source_info.file=(-1);
3820 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.17g]",
3821 image->filename,(double) image->scene);
3822 cache_info->storage_class=image->storage_class;
3823 cache_info->colorspace=image->colorspace;
3824 cache_info->alpha_trait=image->alpha_trait;
3825 cache_info->channels=image->channels;
3826 cache_info->rows=image->rows;
3827 cache_info->columns=image->columns;
3828 status=ResetPixelChannelMap(image,exception);
3829 if (status == MagickFalse)
3830 return(MagickFalse);
3831 cache_info->number_channels=GetPixelChannels(image);
3832 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3833 sizeof(*image->channel_map));
3834 cache_info->metacontent_extent=image->metacontent_extent;
3835 cache_info->mode=mode;
3836 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3837 packet_size=MagickMax(cache_info->number_channels,1)*sizeof(Quantum);
3838 if (cache_info->metacontent_extent != 0)
3839 {
3840 if (HeapOverflowCheckAdd(packet_size,cache_info->metacontent_extent) != MagickFalse)
3841 {
3842 cache_info->storage_class=UndefinedClass;
3843 cache_info->length=0;
3844 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3845 image->filename);
3846 }
3847 packet_size+=cache_info->metacontent_extent;
3848 }
3849 if (CacheOverflowSanityCheckGetSize(number_pixels,packet_size,&length) != MagickFalse)
3850 {
3851 cache_info->storage_class=UndefinedClass;
3852 cache_info->length=0;
3853 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3854 image->filename);
3855 }
3856 columns=(size_t) (length/cache_info->rows/packet_size);
3857 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3858 ((ssize_t) cache_info->rows < 0))
3859 {
3860 cache_info->storage_class=UndefinedClass;
3861 cache_info->length=0;
3862 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3863 image->filename);
3864 }
3865 cache_info->length=length;
3866 if (image->ping != MagickFalse)
3867 {
3868 cache_info->type=PingCache;
3869 return(MagickTrue);
3870 }
3871 status=AcquireMagickResource(AreaResource,(MagickSizeType)
3872 cache_info->columns*cache_info->rows);
3873 if (cache_info->mode == PersistMode)
3874 status=MagickFalse;
3875 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3876 cache_info->metacontent_extent);
3877 if ((status != MagickFalse) &&
3878 (length == (MagickSizeType) ((size_t) length)) &&
3879 ((cache_info->type == UndefinedCache) ||
3880 (cache_info->type == MemoryCache)))
3881 {
3882 status=AcquireMagickResource(MemoryResource,cache_info->length);
3883 if (status != MagickFalse)
3884 {
3885 status=MagickTrue;
3886 if (cache_anonymous_memory <= 0)
3887 {
3888 cache_info->mapped=MagickFalse;
3889 cache_info->pixels=(Quantum *) MagickAssumeAligned(
3890 AcquireAlignedMemory(1,(size_t) cache_info->length));
3891 }
3892 else
3893 {
3894 cache_info->mapped=MagickTrue;
3895 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3896 cache_info->length);
3897 }
3898 if (cache_info->pixels == (Quantum *) NULL)
3899 {
3900 RelinquishMagickResource(MemoryResource,cache_info->length);
3901 cache_info->mapped=source_info.mapped;
3902 cache_info->pixels=source_info.pixels;
3903 }
3904 else
3905 {
3906 /*
3907 Create memory pixel cache.
3908 */
3909 cache_info->type=MemoryCache;
3910 cache_info->metacontent=(void *) NULL;
3911 if (cache_info->metacontent_extent != 0)
3912 cache_info->metacontent=(void *) (cache_info->pixels+
3913 cache_info->number_channels*number_pixels);
3914 if ((source_info.storage_class != UndefinedClass) &&
3915 (mode != ReadMode))
3916 {
3917 status=ClonePixelCacheRepository(cache_info,&source_info,
3918 exception);
3919 RelinquishPixelCachePixels(&source_info);
3920 }
3921 if (cache_info->debug != MagickFalse)
3922 {
3923 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3924 MagickPathExtent,format);
3925 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3926 cache_info->type);
3927 (void) FormatLocaleString(message,MagickPathExtent,
3928 "open %s (%s %s, %.17gx%.17gx%.17g %s)",
3929 cache_info->filename,cache_info->mapped != MagickFalse ?
3930 "Anonymous" : "Heap",type,(double) cache_info->columns,
3931 (double) cache_info->rows,(double)
3932 cache_info->number_channels,format);
3933 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3934 message);
3935 }
3936 cache_info->storage_class=image->storage_class;
3937 if (status == 0)
3938 {
3939 if ((source_info.storage_class != UndefinedClass) &&
3940 (mode != ReadMode))
3941 RelinquishPixelCachePixels(&source_info);
3942 cache_info->type=UndefinedCache;
3943 return(MagickFalse);
3944 }
3945 return(MagickTrue);
3946 }
3947 }
3948 }
3949 status=AcquireMagickResource(DiskResource,cache_info->length);
3950 hosts=(const char *) GetImageRegistry(StringRegistryType,"cache:hosts",
3951 exception);
3952 if ((status == MagickFalse) && (hosts != (const char *) NULL))
3953 {
3954 DistributeCacheInfo
3955 *server_info;
3956
3957 /*
3958 Distribute the pixel cache to a remote server.
3959 */
3960 server_info=AcquireDistributeCacheInfo(exception);
3961 if (server_info != (DistributeCacheInfo *) NULL)
3962 {
3963 status=OpenDistributePixelCache(server_info,image);
3964 if (status == MagickFalse)
3965 {
3966 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3967 GetDistributeCacheHostname(server_info));
3968 server_info=DestroyDistributeCacheInfo(server_info);
3969 }
3970 else
3971 {
3972 /*
3973 Create a distributed pixel cache.
3974 */
3975 status=MagickTrue;
3976 cache_info->type=DistributedCache;
3977 cache_info->server_info=server_info;
3978 (void) FormatLocaleString(cache_info->cache_filename,
3979 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3980 (DistributeCacheInfo *) cache_info->server_info),
3981 GetDistributeCachePort((DistributeCacheInfo *)
3982 cache_info->server_info));
3983 if ((source_info.storage_class != UndefinedClass) &&
3984 (mode != ReadMode))
3985 {
3986 status=ClonePixelCacheRepository(cache_info,&source_info,
3987 exception);
3988 RelinquishPixelCachePixels(&source_info);
3989 }
3990 if (cache_info->debug != MagickFalse)
3991 {
3992 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3993 MagickPathExtent,format);
3994 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3995 cache_info->type);
3996 (void) FormatLocaleString(message,MagickPathExtent,
3997 "open %s (%s[%d], %s, %.17gx%.17gx%.17g %s)",
3998 cache_info->filename,cache_info->cache_filename,
3999 GetDistributeCacheFile((DistributeCacheInfo *)
4000 cache_info->server_info),type,(double) cache_info->columns,
4001 (double) cache_info->rows,(double)
4002 cache_info->number_channels,format);
4003 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4004 message);
4005 }
4006 if (status == 0)
4007 {
4008 if ((source_info.storage_class != UndefinedClass) &&
4009 (mode != ReadMode))
4010 RelinquishPixelCachePixels(&source_info);
4011 cache_info->type=UndefinedCache;
4012 return(MagickFalse);
4013 }
4014 return(MagickTrue);
4015 }
4016 }
4017 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4018 RelinquishPixelCachePixels(&source_info);
4019 cache_info->type=UndefinedCache;
4020 (void) memset(image->channel_map,0,MaxPixelChannels*
4021 sizeof(*image->channel_map));
4022 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4023 "CacheResourcesExhausted","`%s'",image->filename);
4024 return(MagickFalse);
4025 }
4026 /*
4027 Create pixel cache on disk.
4028 */
4029 if (status == MagickFalse)
4030 {
4031 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4032 RelinquishPixelCachePixels(&source_info);
4033 cache_info->type=UndefinedCache;
4034 (void) memset(image->channel_map,0,MaxPixelChannels*
4035 sizeof(*image->channel_map));
4036 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4037 "CacheResourcesExhausted","`%s'",image->filename);
4038 return(MagickFalse);
4039 }
4040 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode) &&
4041 (cache_info->mode != PersistMode))
4042 {
4043 (void) ClosePixelCacheOnDisk(cache_info);
4044 *cache_info->cache_filename='\0';
4045 }
4046 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4047 {
4048 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4049 RelinquishPixelCachePixels(&source_info);
4050 cache_info->type=UndefinedCache;
4051 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4052 image->filename);
4053 return(MagickFalse);
4054 }
4055 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
4056 cache_info->length);
4057 if (status == MagickFalse)
4058 {
4059 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4060 RelinquishPixelCachePixels(&source_info);
4061 cache_info->type=UndefinedCache;
4062 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4063 image->filename);
4064 return(MagickFalse);
4065 }
4066 cache_info->type=DiskCache;
4067 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4068 cache_info->metacontent_extent);
4069 if (length == (MagickSizeType) ((size_t) length))
4070 {
4071 status=AcquireMagickResource(MapResource,cache_info->length);
4072 if (status != MagickFalse)
4073 {
4074 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4075 cache_info->offset,(size_t) cache_info->length);
4076 if (cache_info->pixels == (Quantum *) NULL)
4077 {
4078 cache_info->mapped=source_info.mapped;
4079 cache_info->pixels=source_info.pixels;
4080 RelinquishMagickResource(MapResource,cache_info->length);
4081 }
4082 else
4083 {
4084 /*
4085 Create file-backed memory-mapped pixel cache.
4086 */
4087 (void) ClosePixelCacheOnDisk(cache_info);
4088 cache_info->type=MapCache;
4089 cache_info->mapped=MagickTrue;
4090 cache_info->metacontent=(void *) NULL;
4091 if (cache_info->metacontent_extent != 0)
4092 cache_info->metacontent=(void *) (cache_info->pixels+
4093 cache_info->number_channels*number_pixels);
4094 if ((source_info.storage_class != UndefinedClass) &&
4095 (mode != ReadMode))
4096 {
4097 status=ClonePixelCacheRepository(cache_info,&source_info,
4098 exception);
4099 RelinquishPixelCachePixels(&source_info);
4100 }
4101 if (cache_info->debug != MagickFalse)
4102 {
4103 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
4104 MagickPathExtent,format);
4105 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4106 cache_info->type);
4107 (void) FormatLocaleString(message,MagickPathExtent,
4108 "open %s (%s[%d], %s, %.17gx%.17gx%.17g %s)",
4109 cache_info->filename,cache_info->cache_filename,
4110 cache_info->file,type,(double) cache_info->columns,
4111 (double) cache_info->rows,(double)
4112 cache_info->number_channels,format);
4113 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4114 message);
4115 }
4116 if (status == 0)
4117 {
4118 if ((source_info.storage_class != UndefinedClass) &&
4119 (mode != ReadMode))
4120 RelinquishPixelCachePixels(&source_info);
4121 cache_info->type=UndefinedCache;
4122 return(MagickFalse);
4123 }
4124 return(MagickTrue);
4125 }
4126 }
4127 }
4128 status=MagickTrue;
4129 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4130 {
4131 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
4132 RelinquishPixelCachePixels(&source_info);
4133 }
4134 if (cache_info->debug != MagickFalse)
4135 {
4136 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
4137 MagickPathExtent,format);
4138 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4139 cache_info->type);
4140 (void) FormatLocaleString(message,MagickPathExtent,
4141 "open %s (%s[%d], %s, %.17gx%.17gx%.17g %s)",cache_info->filename,
4142 cache_info->cache_filename,cache_info->file,type,(double)
4143 cache_info->columns,(double) cache_info->rows,(double)
4144 cache_info->number_channels,format);
4145 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4146 }
4147 if (status == 0)
4148 {
4149 cache_info->type=UndefinedCache;
4150 return(MagickFalse);
4151 }
4152 return(MagickTrue);
4153}
4154
4155/*
4156%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4157% %
4158% %
4159% %
4160+ P e r s i s t P i x e l C a c h e %
4161% %
4162% %
4163% %
4164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4165%
4166% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4167% persistent pixel cache is one that resides on disk and is not destroyed
4168% when the program exits.
4169%
4170% The format of the PersistPixelCache() method is:
4171%
4172% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4173% const MagickBooleanType attach,MagickOffsetType *offset,
4174% ExceptionInfo *exception)
4175%
4176% A description of each parameter follows:
4177%
4178% o image: the image.
4179%
4180% o filename: the persistent pixel cache filename.
4181%
4182% o attach: A value other than zero initializes the persistent pixel cache.
4183%
4184% o initialize: A value other than zero initializes the persistent pixel
4185% cache.
4186%
4187% o offset: the offset in the persistent cache to store pixels.
4188%
4189% o exception: return any errors or warnings in this structure.
4190%
4191*/
4192MagickExport MagickBooleanType PersistPixelCache(Image *image,
4193 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4194 ExceptionInfo *exception)
4195{
4196 CacheInfo
4197 *magick_restrict cache_info,
4198 *magick_restrict clone_info;
4199
4200 MagickBooleanType
4201 status;
4202
4203 ssize_t
4204 page_size;
4205
4206 assert(image != (Image *) NULL);
4207 assert(image->signature == MagickCoreSignature);
4208 if (IsEventLogging() != MagickFalse)
4209 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4210 assert(image->cache != (void *) NULL);
4211 assert(filename != (const char *) NULL);
4212 assert(offset != (MagickOffsetType *) NULL);
4213 page_size=GetMagickPageSize();
4214 cache_info=(CacheInfo *) image->cache;
4215 assert(cache_info->signature == MagickCoreSignature);
4216#if defined(MAGICKCORE_OPENCL_SUPPORT)
4217 CopyOpenCLBuffer(cache_info);
4218#endif
4219 if (attach != MagickFalse)
4220 {
4221 /*
4222 Attach existing persistent pixel cache.
4223 */
4224 if (cache_info->debug != MagickFalse)
4225 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4226 "attach persistent cache");
4227 (void) CopyMagickString(cache_info->cache_filename,filename,
4228 MagickPathExtent);
4229 cache_info->type=MapCache;
4230 cache_info->offset=(*offset);
4231 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4232 return(MagickFalse);
4233 *offset=(*offset+(MagickOffsetType) cache_info->length+page_size-
4234 ((MagickOffsetType) cache_info->length % page_size));
4235 return(MagickTrue);
4236 }
4237 /*
4238 Clone persistent pixel cache.
4239 */
4240 status=AcquireMagickResource(DiskResource,cache_info->length);
4241 if (status == MagickFalse)
4242 {
4243 cache_info->type=UndefinedCache;
4244 (void) memset(image->channel_map,0,MaxPixelChannels*
4245 sizeof(*image->channel_map));
4246 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4247 "CacheResourcesExhausted","`%s'",image->filename);
4248 return(MagickFalse);
4249 }
4250 clone_info=(CacheInfo *) ClonePixelCache(cache_info);
4251 clone_info->type=DiskCache;
4252 (void) CopyMagickString(clone_info->cache_filename,filename,MagickPathExtent);
4253 clone_info->file=(-1);
4254 clone_info->storage_class=cache_info->storage_class;
4255 clone_info->colorspace=cache_info->colorspace;
4256 clone_info->alpha_trait=cache_info->alpha_trait;
4257 clone_info->channels=cache_info->channels;
4258 clone_info->columns=cache_info->columns;
4259 clone_info->rows=cache_info->rows;
4260 clone_info->number_channels=cache_info->number_channels;
4261 clone_info->metacontent_extent=cache_info->metacontent_extent;
4262 clone_info->mode=PersistMode;
4263 clone_info->length=cache_info->length;
4264 (void) memcpy(clone_info->channel_map,cache_info->channel_map,
4265 MaxPixelChannels*sizeof(*cache_info->channel_map));
4266 clone_info->offset=(*offset);
4267 status=OpenPixelCacheOnDisk(clone_info,WriteMode);
4268 if (status != MagickFalse)
4269 status=ClonePixelCacheRepository(clone_info,cache_info,exception);
4270 *offset=(*offset+(MagickOffsetType) cache_info->length+page_size-
4271 ((MagickOffsetType) cache_info->length % page_size));
4272 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4273 return(status);
4274}
4275
4276/*
4277%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4278% %
4279% %
4280% %
4281+ 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 %
4282% %
4283% %
4284% %
4285%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4286%
4287% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4288% defined by the region rectangle and returns a pointer to the region. This
4289% region is subsequently transferred from the pixel cache with
4290% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4291% pixels are transferred, otherwise a NULL is returned.
4292%
4293% The format of the QueueAuthenticPixelCacheNexus() method is:
4294%
4295% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4296% const ssize_t y,const size_t columns,const size_t rows,
4297% const MagickBooleanType clone,NexusInfo *nexus_info,
4298% ExceptionInfo *exception)
4299%
4300% A description of each parameter follows:
4301%
4302% o image: the image.
4303%
4304% o x,y,columns,rows: These values define the perimeter of a region of
4305% pixels.
4306%
4307% o nexus_info: the cache nexus to set.
4308%
4309% o clone: clone the pixel cache.
4310%
4311% o exception: return any errors or warnings in this structure.
4312%
4313*/
4314MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4315 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4316 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4317{
4318 CacheInfo
4319 *magick_restrict cache_info;
4320
4321 MagickOffsetType
4322 offset;
4323
4324 MagickSizeType
4325 number_pixels;
4326
4327 Quantum
4328 *magick_restrict pixels;
4329
4330 /*
4331 Validate pixel cache geometry.
4332 */
4333 assert(image != (const Image *) NULL);
4334 assert(image->signature == MagickCoreSignature);
4335 assert(image->cache != (Cache) NULL);
4336 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4337 if (cache_info == (Cache) NULL)
4338 return((Quantum *) NULL);
4339 assert(cache_info->signature == MagickCoreSignature);
4340 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
4341 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4342 (y >= (ssize_t) cache_info->rows))
4343 {
4344 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4345 "PixelsAreNotAuthentic","`%s'",image->filename);
4346 return((Quantum *) NULL);
4347 }
4348 if (IsValidPixelOffset(y,cache_info->columns) == MagickFalse)
4349 return((Quantum *) NULL);
4350 offset=y*(MagickOffsetType) cache_info->columns;
4351 if (IsOffsetOverflow(offset,(MagickOffsetType) x) == MagickFalse)
4352 return((Quantum *) NULL);
4353 offset+=x;
4354 if (offset < 0)
4355 return((Quantum *) NULL);
4356 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4357 offset+=((MagickOffsetType) rows-1)*(MagickOffsetType) cache_info->columns;
4358 if (IsOffsetOverflow(offset,(MagickOffsetType) columns-1) == MagickFalse)
4359 return((Quantum *) NULL);
4360 offset+=(MagickOffsetType) columns-1;
4361 if ((MagickSizeType) offset >= number_pixels)
4362 return((Quantum *) NULL);
4363 /*
4364 Return pixel cache.
4365 */
4366 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,x,y,columns,rows,
4367 ((image->channels & WriteMaskChannel) != 0) ||
4368 ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
4369 nexus_info,exception);
4370 return(pixels);
4371}
4372
4373/*
4374%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4375% %
4376% %
4377% %
4378+ 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 %
4379% %
4380% %
4381% %
4382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4383%
4384% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4385% defined by the region rectangle and returns a pointer to the region. This
4386% region is subsequently transferred from the pixel cache with
4387% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4388% pixels are transferred, otherwise a NULL is returned.
4389%
4390% The format of the QueueAuthenticPixelsCache() method is:
4391%
4392% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4393% const ssize_t y,const size_t columns,const size_t rows,
4394% ExceptionInfo *exception)
4395%
4396% A description of each parameter follows:
4397%
4398% o image: the image.
4399%
4400% o x,y,columns,rows: These values define the perimeter of a region of
4401% pixels.
4402%
4403% o exception: return any errors or warnings in this structure.
4404%
4405*/
4406static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4407 const ssize_t y,const size_t columns,const size_t rows,
4408 ExceptionInfo *exception)
4409{
4410 CacheInfo
4411 *magick_restrict cache_info;
4412
4413 const int
4414 id = GetOpenMPThreadId();
4415
4416 Quantum
4417 *magick_restrict pixels;
4418
4419 assert(image != (const Image *) NULL);
4420 assert(image->signature == MagickCoreSignature);
4421 assert(image->cache != (Cache) NULL);
4422 cache_info=(CacheInfo *) image->cache;
4423 assert(cache_info->signature == MagickCoreSignature);
4424 assert(id < (int) cache_info->number_threads);
4425 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4426 cache_info->nexus_info[id],exception);
4427 return(pixels);
4428}
4429
4430/*
4431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4432% %
4433% %
4434% %
4435% Q u e u e A u t h e n t i c P i x e l s %
4436% %
4437% %
4438% %
4439%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4440%
4441% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4442% successfully initialized a pointer to a Quantum array representing the
4443% region is returned, otherwise NULL is returned. The returned pointer may
4444% point to a temporary working buffer for the pixels or it may point to the
4445% final location of the pixels in memory.
4446%
4447% Write-only access means that any existing pixel values corresponding to
4448% the region are ignored. This is useful if the initial image is being
4449% created from scratch, or if the existing pixel values are to be
4450% completely replaced without need to refer to their preexisting values.
4451% The application is free to read and write the pixel buffer returned by
4452% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4453% initialize the pixel array values. Initializing pixel array values is the
4454% application's responsibility.
4455%
4456% Performance is maximized if the selected region is part of one row, or
4457% one or more full rows, since then there is opportunity to access the
4458% pixels in-place (without a copy) if the image is in memory, or in a
4459% memory-mapped file. The returned pointer must *never* be deallocated
4460% by the user.
4461%
4462% Pixels accessed via the returned pointer represent a simple array of type
4463% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4464% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4465% obtain the meta-content (of type void) corresponding to the region.
4466% Once the Quantum (and/or Quantum) array has been updated, the
4467% changes must be saved back to the underlying image using
4468% SyncAuthenticPixels() or they may be lost.
4469%
4470% The format of the QueueAuthenticPixels() method is:
4471%
4472% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4473% const ssize_t y,const size_t columns,const size_t rows,
4474% ExceptionInfo *exception)
4475%
4476% A description of each parameter follows:
4477%
4478% o image: the image.
4479%
4480% o x,y,columns,rows: These values define the perimeter of a region of
4481% pixels.
4482%
4483% o exception: return any errors or warnings in this structure.
4484%
4485*/
4486MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4487 const ssize_t y,const size_t columns,const size_t rows,
4488 ExceptionInfo *exception)
4489{
4490 CacheInfo
4491 *magick_restrict cache_info;
4492
4493 const int
4494 id = GetOpenMPThreadId();
4495
4496 Quantum
4497 *magick_restrict pixels;
4498
4499 assert(image != (Image *) NULL);
4500 assert(image->signature == MagickCoreSignature);
4501 assert(image->cache != (Cache) NULL);
4502 cache_info=(CacheInfo *) image->cache;
4503 assert(cache_info->signature == MagickCoreSignature);
4504 if (cache_info->methods.queue_authentic_pixels_handler !=
4505 (QueueAuthenticPixelsHandler) NULL)
4506 {
4507 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4508 columns,rows,exception);
4509 return(pixels);
4510 }
4511 assert(id < (int) cache_info->number_threads);
4512 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4513 cache_info->nexus_info[id],exception);
4514 return(pixels);
4515}
4516
4517/*
4518%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4519% %
4520% %
4521% %
4522+ 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 %
4523% %
4524% %
4525% %
4526%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4527%
4528% ReadPixelCacheMetacontent() reads metacontent from the specified region of
4529% the pixel cache.
4530%
4531% The format of the ReadPixelCacheMetacontent() method is:
4532%
4533% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4534% NexusInfo *nexus_info,ExceptionInfo *exception)
4535%
4536% A description of each parameter follows:
4537%
4538% o cache_info: the pixel cache.
4539%
4540% o nexus_info: the cache nexus to read the metacontent.
4541%
4542% o exception: return any errors or warnings in this structure.
4543%
4544*/
4545
4546static inline MagickOffsetType ReadPixelCacheRegion(
4547 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4548 const MagickSizeType length,unsigned char *magick_restrict buffer)
4549{
4550 MagickOffsetType
4551 i;
4552
4553 ssize_t
4554 count = 0;
4555
4556 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4557 return((MagickOffsetType) -1);
4558 for (i=0; i < (MagickOffsetType) length; i+=count)
4559 {
4560 count=MagickRead(cache_info->file,buffer+i,(size_t) MagickMin(length-
4561 (MagickSizeType) i,(size_t) MagickMaxBufferExtent));
4562 if (count <= 0)
4563 break;
4564 }
4565 return(i);
4566}
4567
4568static MagickBooleanType ReadPixelCacheMetacontent(
4569 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4570 ExceptionInfo *exception)
4571{
4572 MagickOffsetType
4573 count,
4574 offset;
4575
4576 MagickSizeType
4577 extent,
4578 length;
4579
4580 ssize_t
4581 y;
4582
4583 unsigned char
4584 *magick_restrict q;
4585
4586 size_t
4587 rows;
4588
4589 if (cache_info->metacontent_extent == 0)
4590 return(MagickFalse);
4591 if (nexus_info->authentic_pixel_cache != MagickFalse)
4592 return(MagickTrue);
4593 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
4594 return(MagickFalse);
4595 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
4596 nexus_info->region.x;
4597 length=(MagickSizeType) nexus_info->region.width*
4598 cache_info->metacontent_extent;
4599 extent=length*nexus_info->region.height;
4600 rows=nexus_info->region.height;
4601 y=0;
4602 q=(unsigned char *) nexus_info->metacontent;
4603 switch (cache_info->type)
4604 {
4605 case MemoryCache:
4606 case MapCache:
4607 {
4608 unsigned char
4609 *magick_restrict p;
4610
4611 /*
4612 Read meta-content from memory.
4613 */
4614 if ((cache_info->columns == nexus_info->region.width) &&
4615 (extent == (MagickSizeType) ((size_t) extent)))
4616 {
4617 length=extent;
4618 rows=1UL;
4619 }
4620 p=(unsigned char *) cache_info->metacontent+offset*(MagickOffsetType)
4621 cache_info->metacontent_extent;
4622 for (y=0; y < (ssize_t) rows; y++)
4623 {
4624 (void) memcpy(q,p,(size_t) length);
4625 p+=(ptrdiff_t) cache_info->metacontent_extent*cache_info->columns;
4626 q+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
4627 }
4628 break;
4629 }
4630 case DiskCache:
4631 {
4632 /*
4633 Read meta content from disk.
4634 */
4635 LockSemaphoreInfo(cache_info->file_semaphore);
4636 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4637 {
4638 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4639 cache_info->cache_filename);
4640 UnlockSemaphoreInfo(cache_info->file_semaphore);
4641 return(MagickFalse);
4642 }
4643 if ((cache_info->columns == nexus_info->region.width) &&
4644 (extent <= MagickMaxBufferExtent))
4645 {
4646 length=extent;
4647 rows=1UL;
4648 }
4649 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4650 for (y=0; y < (ssize_t) rows; y++)
4651 {
4652 count=ReadPixelCacheRegion(cache_info,cache_info->offset+
4653 (MagickOffsetType) extent*(MagickOffsetType)
4654 cache_info->number_channels*(MagickOffsetType) sizeof(Quantum)+offset*
4655 (MagickOffsetType) cache_info->metacontent_extent,length,
4656 (unsigned char *) q);
4657 if (count != (MagickOffsetType) length)
4658 break;
4659 offset+=(MagickOffsetType) cache_info->columns;
4660 q+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
4661 }
4662 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4663 (void) ClosePixelCacheOnDisk(cache_info);
4664 UnlockSemaphoreInfo(cache_info->file_semaphore);
4665 break;
4666 }
4667 case DistributedCache:
4668 {
4669 RectangleInfo
4670 region;
4671
4672 /*
4673 Read metacontent from distributed cache.
4674 */
4675 LockSemaphoreInfo(cache_info->file_semaphore);
4676 region=nexus_info->region;
4677 if ((cache_info->columns != nexus_info->region.width) ||
4678 (extent > MagickMaxBufferExtent))
4679 region.height=1UL;
4680 else
4681 {
4682 length=extent;
4683 rows=1UL;
4684 }
4685 for (y=0; y < (ssize_t) rows; y++)
4686 {
4687 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4688 cache_info->server_info,&region,length,(unsigned char *) q);
4689 if (count != (MagickOffsetType) length)
4690 break;
4691 q+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
4692 region.y++;
4693 }
4694 UnlockSemaphoreInfo(cache_info->file_semaphore);
4695 break;
4696 }
4697 default:
4698 break;
4699 }
4700 if (y < (ssize_t) rows)
4701 {
4702 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4703 cache_info->cache_filename);
4704 return(MagickFalse);
4705 }
4706 if ((cache_info->debug != MagickFalse) &&
4707 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4708 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4709 "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
4710 nexus_info->region.width,(double) nexus_info->region.height,(double)
4711 nexus_info->region.x,(double) nexus_info->region.y);
4712 return(MagickTrue);
4713}
4714
4715/*
4716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4717% %
4718% %
4719% %
4720+ R e a d P i x e l C a c h e P i x e l s %
4721% %
4722% %
4723% %
4724%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4725%
4726% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4727% cache.
4728%
4729% The format of the ReadPixelCachePixels() method is:
4730%
4731% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4732% NexusInfo *nexus_info,ExceptionInfo *exception)
4733%
4734% A description of each parameter follows:
4735%
4736% o cache_info: the pixel cache.
4737%
4738% o nexus_info: the cache nexus to read the pixels.
4739%
4740% o exception: return any errors or warnings in this structure.
4741%
4742*/
4743static MagickBooleanType ReadPixelCachePixels(
4744 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4745 ExceptionInfo *exception)
4746{
4747 MagickOffsetType
4748 count,
4749 offset;
4750
4751 MagickSizeType
4752 extent,
4753 length;
4754
4755 Quantum
4756 *magick_restrict q;
4757
4758 size_t
4759 number_channels,
4760 rows;
4761
4762 ssize_t
4763 y;
4764
4765 if (nexus_info->authentic_pixel_cache != MagickFalse)
4766 return(MagickTrue);
4767 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
4768 return(MagickFalse);
4769 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns;
4770 if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4771 return(MagickFalse);
4772 offset+=nexus_info->region.x;
4773 number_channels=cache_info->number_channels;
4774 length=(MagickSizeType) number_channels*nexus_info->region.width*
4775 sizeof(Quantum);
4776 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4777 return(MagickFalse);
4778 rows=nexus_info->region.height;
4779 extent=length*rows;
4780 if ((extent == 0) || ((extent/length) != rows))
4781 return(MagickFalse);
4782 y=0;
4783 q=nexus_info->pixels;
4784 switch (cache_info->type)
4785 {
4786 case MemoryCache:
4787 case MapCache:
4788 {
4789 Quantum
4790 *magick_restrict p;
4791
4792 /*
4793 Read pixels from memory.
4794 */
4795 if ((cache_info->columns == nexus_info->region.width) &&
4796 (extent == (MagickSizeType) ((size_t) extent)))
4797 {
4798 length=extent;
4799 rows=1UL;
4800 }
4801 p=cache_info->pixels+(MagickOffsetType) cache_info->number_channels*
4802 offset;
4803 for (y=0; y < (ssize_t) rows; y++)
4804 {
4805 (void) memcpy(q,p,(size_t) length);
4806 p+=(ptrdiff_t) cache_info->number_channels*cache_info->columns;
4807 q+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
4808 }
4809 break;
4810 }
4811 case DiskCache:
4812 {
4813 /*
4814 Read pixels from disk.
4815 */
4816 LockSemaphoreInfo(cache_info->file_semaphore);
4817 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4818 {
4819 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4820 cache_info->cache_filename);
4821 UnlockSemaphoreInfo(cache_info->file_semaphore);
4822 return(MagickFalse);
4823 }
4824 if ((cache_info->columns == nexus_info->region.width) &&
4825 (extent <= MagickMaxBufferExtent))
4826 {
4827 length=extent;
4828 rows=1UL;
4829 }
4830 for (y=0; y < (ssize_t) rows; y++)
4831 {
4832 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4833 (MagickOffsetType) cache_info->number_channels*(MagickOffsetType)
4834 sizeof(*q),length,(unsigned char *) q);
4835 if (count != (MagickOffsetType) length)
4836 break;
4837 offset+=(MagickOffsetType) cache_info->columns;
4838 q+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
4839 }
4840 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4841 (void) ClosePixelCacheOnDisk(cache_info);
4842 UnlockSemaphoreInfo(cache_info->file_semaphore);
4843 break;
4844 }
4845 case DistributedCache:
4846 {
4847 RectangleInfo
4848 region;
4849
4850 /*
4851 Read pixels from distributed cache.
4852 */
4853 LockSemaphoreInfo(cache_info->file_semaphore);
4854 region=nexus_info->region;
4855 if ((cache_info->columns != nexus_info->region.width) ||
4856 (extent > MagickMaxBufferExtent))
4857 region.height=1UL;
4858 else
4859 {
4860 length=extent;
4861 rows=1UL;
4862 }
4863 for (y=0; y < (ssize_t) rows; y++)
4864 {
4865 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4866 cache_info->server_info,&region,length,(unsigned char *) q);
4867 if (count != (MagickOffsetType) length)
4868 break;
4869 q+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
4870 region.y++;
4871 }
4872 UnlockSemaphoreInfo(cache_info->file_semaphore);
4873 break;
4874 }
4875 default:
4876 break;
4877 }
4878 if (y < (ssize_t) rows)
4879 {
4880 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4881 cache_info->cache_filename);
4882 return(MagickFalse);
4883 }
4884 if ((cache_info->debug != MagickFalse) &&
4885 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4886 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4887 "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
4888 nexus_info->region.width,(double) nexus_info->region.height,(double)
4889 nexus_info->region.x,(double) nexus_info->region.y);
4890 return(MagickTrue);
4891}
4892
4893/*
4894%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4895% %
4896% %
4897% %
4898+ R e f e r e n c e P i x e l C a c h e %
4899% %
4900% %
4901% %
4902%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4903%
4904% ReferencePixelCache() increments the reference count associated with the
4905% pixel cache returning a pointer to the cache.
4906%
4907% The format of the ReferencePixelCache method is:
4908%
4909% Cache ReferencePixelCache(Cache cache_info)
4910%
4911% A description of each parameter follows:
4912%
4913% o cache_info: the pixel cache.
4914%
4915*/
4916MagickPrivate Cache ReferencePixelCache(Cache cache)
4917{
4918 CacheInfo
4919 *magick_restrict cache_info;
4920
4921 assert(cache != (Cache *) NULL);
4922 cache_info=(CacheInfo *) cache;
4923 assert(cache_info->signature == MagickCoreSignature);
4924 LockSemaphoreInfo(cache_info->semaphore);
4925 cache_info->reference_count++;
4926 UnlockSemaphoreInfo(cache_info->semaphore);
4927 return(cache_info);
4928}
4929
4930/*
4931%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4932% %
4933% %
4934% %
4935+ R e s e t P i x e l C a c h e C h a n n e l s %
4936% %
4937% %
4938% %
4939%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4940%
4941% ResetPixelCacheChannels() resets the pixel cache channels.
4942%
4943% The format of the ResetPixelCacheChannels method is:
4944%
4945% void ResetPixelCacheChannels(Image *)
4946%
4947% A description of each parameter follows:
4948%
4949% o image: the image.
4950%
4951*/
4952MagickPrivate void ResetPixelCacheChannels(Image *image)
4953{
4954 CacheInfo
4955 *magick_restrict cache_info;
4956
4957 assert(image != (const Image *) NULL);
4958 assert(image->signature == MagickCoreSignature);
4959 assert(image->cache != (Cache) NULL);
4960 cache_info=(CacheInfo *) image->cache;
4961 assert(cache_info->signature == MagickCoreSignature);
4962 cache_info->number_channels=GetPixelChannels(image);
4963}
4964
4965/*
4966%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4967% %
4968% %
4969% %
4970+ 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 %
4971% %
4972% %
4973% %
4974%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4975%
4976% ResetCacheAnonymousMemory() resets the anonymous_memory value.
4977%
4978% The format of the ResetCacheAnonymousMemory method is:
4979%
4980% void ResetCacheAnonymousMemory(void)
4981%
4982*/
4983MagickPrivate void ResetCacheAnonymousMemory(void)
4984{
4985 cache_anonymous_memory=0;
4986}
4987
4988/*
4989%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4990% %
4991% %
4992% %
4993% R e s h a p e P i x e l C a c h e %
4994% %
4995% %
4996% %
4997%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4998%
4999% ReshapePixelCache() reshapes an existing pixel cache.
5000%
5001% The format of the ReshapePixelCache() method is:
5002%
5003% MagickBooleanType ReshapePixelCache(Image *image,const size_t columns,
5004% const size_t rows,ExceptionInfo *exception)
5005%
5006% A description of each parameter follows:
5007%
5008% o image: the image.
5009%
5010% o columns: the number of columns in the reshaped pixel cache.
5011%
5012% o rows: number of rows in the reshaped pixel cache.
5013%
5014% o exception: return any errors or warnings in this structure.
5015%
5016*/
5017MagickExport MagickBooleanType ReshapePixelCache(Image *image,
5018 const size_t columns,const size_t rows,ExceptionInfo *exception)
5019{
5020 CacheInfo
5021 *cache_info;
5022
5023 MagickSizeType
5024 extent;
5025
5026 assert(image != (Image *) NULL);
5027 assert(image->signature == MagickCoreSignature);
5028 if (IsEventLogging() != MagickFalse)
5029 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5030 assert(image->cache != (void *) NULL);
5031 extent=(MagickSizeType) columns*rows;
5032 if (extent > ((MagickSizeType) image->columns*image->rows))
5033 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
5034 image->filename);
5035 image->columns=columns;
5036 image->rows=rows;
5037 cache_info=(CacheInfo *) image->cache;
5038 cache_info->columns=columns;
5039 cache_info->rows=rows;
5040 return(SyncImagePixelCache(image,exception));
5041}
5042
5043/*
5044%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5045% %
5046% %
5047% %
5048+ S e t P i x e l C a c h e M e t h o d s %
5049% %
5050% %
5051% %
5052%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5053%
5054% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
5055%
5056% The format of the SetPixelCacheMethods() method is:
5057%
5058% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
5059%
5060% A description of each parameter follows:
5061%
5062% o cache: the pixel cache.
5063%
5064% o cache_methods: Specifies a pointer to a CacheMethods structure.
5065%
5066*/
5067MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
5068{
5069 CacheInfo
5070 *magick_restrict cache_info;
5071
5072 GetOneAuthenticPixelFromHandler
5073 get_one_authentic_pixel_from_handler;
5074
5075 GetOneVirtualPixelFromHandler
5076 get_one_virtual_pixel_from_handler;
5077
5078 /*
5079 Set cache pixel methods.
5080 */
5081 assert(cache != (Cache) NULL);
5082 assert(cache_methods != (CacheMethods *) NULL);
5083 cache_info=(CacheInfo *) cache;
5084 assert(cache_info->signature == MagickCoreSignature);
5085 if (IsEventLogging() != MagickFalse)
5086 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5087 cache_info->filename);
5088 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
5089 cache_info->methods.get_virtual_pixel_handler=
5090 cache_methods->get_virtual_pixel_handler;
5091 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
5092 cache_info->methods.destroy_pixel_handler=
5093 cache_methods->destroy_pixel_handler;
5094 if (cache_methods->get_virtual_metacontent_from_handler !=
5095 (GetVirtualMetacontentFromHandler) NULL)
5096 cache_info->methods.get_virtual_metacontent_from_handler=
5097 cache_methods->get_virtual_metacontent_from_handler;
5098 if (cache_methods->get_authentic_pixels_handler !=
5099 (GetAuthenticPixelsHandler) NULL)
5100 cache_info->methods.get_authentic_pixels_handler=
5101 cache_methods->get_authentic_pixels_handler;
5102 if (cache_methods->queue_authentic_pixels_handler !=
5103 (QueueAuthenticPixelsHandler) NULL)
5104 cache_info->methods.queue_authentic_pixels_handler=
5105 cache_methods->queue_authentic_pixels_handler;
5106 if (cache_methods->sync_authentic_pixels_handler !=
5107 (SyncAuthenticPixelsHandler) NULL)
5108 cache_info->methods.sync_authentic_pixels_handler=
5109 cache_methods->sync_authentic_pixels_handler;
5110 if (cache_methods->get_authentic_pixels_from_handler !=
5111 (GetAuthenticPixelsFromHandler) NULL)
5112 cache_info->methods.get_authentic_pixels_from_handler=
5113 cache_methods->get_authentic_pixels_from_handler;
5114 if (cache_methods->get_authentic_metacontent_from_handler !=
5115 (GetAuthenticMetacontentFromHandler) NULL)
5116 cache_info->methods.get_authentic_metacontent_from_handler=
5117 cache_methods->get_authentic_metacontent_from_handler;
5118 get_one_virtual_pixel_from_handler=
5119 cache_info->methods.get_one_virtual_pixel_from_handler;
5120 if (get_one_virtual_pixel_from_handler !=
5121 (GetOneVirtualPixelFromHandler) NULL)
5122 cache_info->methods.get_one_virtual_pixel_from_handler=
5123 cache_methods->get_one_virtual_pixel_from_handler;
5124 get_one_authentic_pixel_from_handler=
5125 cache_methods->get_one_authentic_pixel_from_handler;
5126 if (get_one_authentic_pixel_from_handler !=
5127 (GetOneAuthenticPixelFromHandler) NULL)
5128 cache_info->methods.get_one_authentic_pixel_from_handler=
5129 cache_methods->get_one_authentic_pixel_from_handler;
5130}
5131
5132/*
5133%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5134% %
5135% %
5136% %
5137+ S e t P i x e l C a c h e N e x u s P i x e l s %
5138% %
5139% %
5140% %
5141%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5142%
5143% SetPixelCacheNexusPixels() defines the region of the cache for the
5144% specified cache nexus.
5145%
5146% The format of the SetPixelCacheNexusPixels() method is:
5147%
5148% Quantum SetPixelCacheNexusPixels(
5149% const CacheInfo *magick_restrict cache_info,const MapMode mode,
5150% const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5151% const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5152% ExceptionInfo *exception)
5153%
5154% A description of each parameter follows:
5155%
5156% o cache_info: the pixel cache.
5157%
5158% o mode: ReadMode, WriteMode, or IOMode.
5159%
5160% o x,y,width,height: define the region of this particular cache nexus.
5161%
5162% o buffered: if true, nexus pixels are buffered.
5163%
5164% o nexus_info: the cache nexus to set.
5165%
5166% o exception: return any errors or warnings in this structure.
5167%
5168*/
5169
5170static inline MagickBooleanType AcquireCacheNexusPixels(
5171 const CacheInfo *magick_restrict cache_info,const MagickSizeType length,
5172 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5173{
5174 if (length != (MagickSizeType) ((size_t) length))
5175 {
5176 (void) ThrowMagickException(exception,GetMagickModule(),
5177 ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
5178 cache_info->filename);
5179 return(MagickFalse);
5180 }
5181 nexus_info->length=0;
5182 nexus_info->mapped=MagickFalse;
5183 if (cache_anonymous_memory <= 0)
5184 {
5185 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
5186 (size_t) length));
5187 if (nexus_info->cache != (Quantum *) NULL)
5188 (void) memset(nexus_info->cache,0,(size_t) length);
5189 }
5190 else
5191 {
5192 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t) length);
5193 if (nexus_info->cache != (Quantum *) NULL)
5194 nexus_info->mapped=MagickTrue;
5195 }
5196 if (nexus_info->cache == (Quantum *) NULL)
5197 {
5198 (void) ThrowMagickException(exception,GetMagickModule(),
5199 ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
5200 cache_info->filename);
5201 return(MagickFalse);
5202 }
5203 nexus_info->length=length;
5204 return(MagickTrue);
5205}
5206
5207static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
5208 const MapMode mode)
5209{
5210 if (nexus_info->length < CACHE_LINE_SIZE)
5211 return;
5212 if (mode == ReadMode)
5213 {
5214 MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,
5215 0,1);
5216 return;
5217 }
5218 MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,1,1);
5219}
5220
5221static Quantum *SetPixelCacheNexusPixels(
5222 const CacheInfo *magick_restrict cache_info,const MapMode mode,
5223 const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5224 const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5225 ExceptionInfo *exception)
5226{
5227 MagickBooleanType
5228 status;
5229
5230 MagickSizeType
5231 length,
5232 number_pixels;
5233
5234 assert(cache_info != (const CacheInfo *) NULL);
5235 assert(cache_info->signature == MagickCoreSignature);
5236 if (cache_info->type == UndefinedCache)
5237 return((Quantum *) NULL);
5238 assert(nexus_info->signature == MagickCoreSignature);
5239 (void) memset(&nexus_info->region,0,sizeof(nexus_info->region));
5240 if ((width == 0) || (height == 0))
5241 {
5242 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
5243 "NoPixelsDefinedInCache","`%s'",cache_info->filename);
5244 return((Quantum *) NULL);
5245 }
5246 if (((MagickSizeType) width > cache_info->width_limit) ||
5247 ((MagickSizeType) height > cache_info->height_limit))
5248 {
5249 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
5250 "WidthOrHeightExceedsLimit","`%s'",cache_info->filename);
5251 return((Quantum *) NULL);
5252 }
5253 if ((IsValidPixelOffset(x,width) == MagickFalse) ||
5254 (IsValidPixelOffset(y,height) == MagickFalse))
5255 {
5256 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
5257 "InvalidPixel","`%s'",cache_info->filename);
5258 return((Quantum *) NULL);
5259 }
5260 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
5261 (buffered == MagickFalse))
5262 {
5263 if (((x >= 0) && (y >= 0) &&
5264 (((ssize_t) height+y-1) < (ssize_t) cache_info->rows)) &&
5265 (((x == 0) && (width == cache_info->columns)) || ((height == 1) &&
5266 (((ssize_t) width+x-1) < (ssize_t) cache_info->columns))))
5267 {
5268 MagickOffsetType
5269 offset;
5270
5271 /*
5272 Pixels are accessed directly from memory.
5273 */
5274 if (IsValidPixelOffset(y,cache_info->columns) == MagickFalse)
5275 return((Quantum *) NULL);
5276 offset=y*(MagickOffsetType) cache_info->columns+x;
5277 nexus_info->pixels=cache_info->pixels+(MagickOffsetType)
5278 cache_info->number_channels*offset;
5279 nexus_info->metacontent=(void *) NULL;
5280 if (cache_info->metacontent_extent != 0)
5281 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5282 offset*(MagickOffsetType) cache_info->metacontent_extent;
5283 nexus_info->region.width=width;
5284 nexus_info->region.height=height;
5285 nexus_info->region.x=x;
5286 nexus_info->region.y=y;
5287 nexus_info->authentic_pixel_cache=MagickTrue;
5288 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5289 return(nexus_info->pixels);
5290 }
5291 }
5292 /*
5293 Pixels are stored in a staging region until they are synced to the cache.
5294 */
5295 if (CacheOverflowSanityCheckGetSize(width,height,&number_pixels) != MagickFalse)
5296 {
5297 (void) ThrowMagickException(exception,GetMagickModule(),
5298 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5299 cache_info->filename);
5300 return((Quantum *) NULL);
5301 }
5302 {
5303 MagickSizeType
5304 extent,
5305 packets;
5306
5307 packets=MagickMax(number_pixels,MagickMax(cache_info->columns,
5308 cache_info->rows));
5309 if ((CacheOverflowSanityCheckGetSize(packets,cache_info->number_channels,&length) != MagickFalse) ||
5310 (CacheOverflowSanityCheckGetSize(length,sizeof(*nexus_info->pixels),&length) != MagickFalse))
5311 {
5312 (void) ThrowMagickException(exception,GetMagickModule(),
5313 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5314 cache_info->filename);
5315 return((Quantum *) NULL);
5316 }
5317 if (cache_info->metacontent_extent != 0)
5318 {
5319 if ((CacheOverflowSanityCheckGetSize(number_pixels,cache_info->metacontent_extent,&extent) != MagickFalse) ||
5320 (extent > (MagickSizeType) (~((MagickSizeType) 0))-length))
5321 {
5322 (void) ThrowMagickException(exception,GetMagickModule(),
5323 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5324 cache_info->filename);
5325 return((Quantum *) NULL);
5326 }
5327 length+=extent;
5328 }
5329 }
5330 status=MagickTrue;
5331 if (nexus_info->cache == (Quantum *) NULL)
5332 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5333 else
5334 if (nexus_info->length < length)
5335 {
5336 RelinquishCacheNexusPixels(nexus_info);
5337 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5338 }
5339 if (status == MagickFalse)
5340 return((Quantum *) NULL);
5341 nexus_info->pixels=nexus_info->cache;
5342 nexus_info->metacontent=(void *) NULL;
5343 if (cache_info->metacontent_extent != 0)
5344 nexus_info->metacontent=(void *) (nexus_info->pixels+
5345 cache_info->number_channels*number_pixels);
5346 nexus_info->region.width=width;
5347 nexus_info->region.height=height;
5348 nexus_info->region.x=x;
5349 nexus_info->region.y=y;
5350 nexus_info->authentic_pixel_cache=cache_info->type == PingCache ?
5351 MagickTrue : MagickFalse;
5352 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5353 return(nexus_info->pixels);
5354}
5355
5356/*
5357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5358% %
5359% %
5360% %
5361% 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 %
5362% %
5363% %
5364% %
5365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5366%
5367% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5368% pixel cache and returns the previous setting. A virtual pixel is any pixel
5369% access that is outside the boundaries of the image cache.
5370%
5371% The format of the SetPixelCacheVirtualMethod() method is:
5372%
5373% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5374% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5375%
5376% A description of each parameter follows:
5377%
5378% o image: the image.
5379%
5380% o virtual_pixel_method: choose the type of virtual pixel.
5381%
5382% o exception: return any errors or warnings in this structure.
5383%
5384*/
5385
5386static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
5387 ExceptionInfo *exception)
5388{
5389 CacheView
5390 *magick_restrict image_view;
5391
5392 MagickBooleanType
5393 status;
5394
5395 ssize_t
5396 y;
5397
5398 assert(image != (Image *) NULL);
5399 assert(image->signature == MagickCoreSignature);
5400 if (IsEventLogging() != MagickFalse)
5401 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5402 assert(image->cache != (Cache) NULL);
5403 image->alpha_trait=BlendPixelTrait;
5404 status=MagickTrue;
5405 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
5406#if defined(MAGICKCORE_OPENMP_SUPPORT)
5407 #pragma omp parallel for schedule(static) shared(status) \
5408 magick_number_threads(image,image,image->rows,2)
5409#endif
5410 for (y=0; y < (ssize_t) image->rows; y++)
5411 {
5412 Quantum
5413 *magick_restrict q;
5414
5415 ssize_t
5416 x;
5417
5418 if (status == MagickFalse)
5419 continue;
5420 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5421 if (q == (Quantum *) NULL)
5422 {
5423 status=MagickFalse;
5424 continue;
5425 }
5426 for (x=0; x < (ssize_t) image->columns; x++)
5427 {
5428 SetPixelAlpha(image,alpha,q);
5429 q+=(ptrdiff_t) GetPixelChannels(image);
5430 }
5431 status=SyncCacheViewAuthenticPixels(image_view,exception);
5432 }
5433 image_view=DestroyCacheView(image_view);
5434 return(status);
5435}
5436
5437MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5438 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5439{
5440 CacheInfo
5441 *magick_restrict cache_info;
5442
5443 VirtualPixelMethod
5444 method;
5445
5446 assert(image != (Image *) NULL);
5447 assert(image->signature == MagickCoreSignature);
5448 if (IsEventLogging() != MagickFalse)
5449 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5450 assert(image->cache != (Cache) NULL);
5451 cache_info=(CacheInfo *) image->cache;
5452 assert(cache_info->signature == MagickCoreSignature);
5453 method=cache_info->virtual_pixel_method;
5454 cache_info->virtual_pixel_method=virtual_pixel_method;
5455 if ((image->columns != 0) && (image->rows != 0))
5456 switch (virtual_pixel_method)
5457 {
5458 case BackgroundVirtualPixelMethod:
5459 {
5460 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
5461 ((image->alpha_trait & BlendPixelTrait) == 0))
5462 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5463 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
5464 (IsGrayColorspace(image->colorspace) != MagickFalse))
5465 (void) SetImageColorspace(image,sRGBColorspace,exception);
5466 break;
5467 }
5468 case TransparentVirtualPixelMethod:
5469 {
5470 if ((image->alpha_trait & BlendPixelTrait) == 0)
5471 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5472 break;
5473 }
5474 default:
5475 break;
5476 }
5477 return(method);
5478}
5479
5480#if defined(MAGICKCORE_OPENCL_SUPPORT)
5481/*
5482%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5483% %
5484% %
5485% %
5486+ 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 %
5487% %
5488% %
5489% %
5490%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5491%
5492% SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
5493% been completed and updates the host memory.
5494%
5495% The format of the SyncAuthenticOpenCLBuffer() method is:
5496%
5497% void SyncAuthenticOpenCLBuffer(const Image *image)
5498%
5499% A description of each parameter follows:
5500%
5501% o image: the image.
5502%
5503*/
5504
5505static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5506{
5507 assert(cache_info != (CacheInfo *) NULL);
5508 assert(cache_info->signature == MagickCoreSignature);
5509 if ((cache_info->type != MemoryCache) ||
5510 (cache_info->opencl == (MagickCLCacheInfo) NULL))
5511 return;
5512 /*
5513 Ensure single threaded access to OpenCL environment.
5514 */
5515 LockSemaphoreInfo(cache_info->semaphore);
5516 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
5517 UnlockSemaphoreInfo(cache_info->semaphore);
5518}
5519
5520MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5521{
5522 CacheInfo
5523 *magick_restrict cache_info;
5524
5525 assert(image != (const Image *) NULL);
5526 cache_info=(CacheInfo *) image->cache;
5527 CopyOpenCLBuffer(cache_info);
5528}
5529#endif
5530
5531/*
5532%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5533% %
5534% %
5535% %
5536+ 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 %
5537% %
5538% %
5539% %
5540%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5541%
5542% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5543% in-memory or disk cache. The method returns MagickTrue if the pixel region
5544% is synced, otherwise MagickFalse.
5545%
5546% The format of the SyncAuthenticPixelCacheNexus() method is:
5547%
5548% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5549% NexusInfo *nexus_info,ExceptionInfo *exception)
5550%
5551% A description of each parameter follows:
5552%
5553% o image: the image.
5554%
5555% o nexus_info: the cache nexus to sync.
5556%
5557% o exception: return any errors or warnings in this structure.
5558%
5559*/
5560MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5561 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5562{
5563 CacheInfo
5564 *magick_restrict cache_info;
5565
5566 MagickBooleanType
5567 status;
5568
5569 /*
5570 Transfer pixels to the cache.
5571 */
5572 assert(image != (Image *) NULL);
5573 assert(image->signature == MagickCoreSignature);
5574 if (image->cache == (Cache) NULL)
5575 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5576 cache_info=(CacheInfo *) image->cache;
5577 assert(cache_info->signature == MagickCoreSignature);
5578 if (cache_info->type == UndefinedCache)
5579 return(MagickFalse);
5580 if ((image->mask_trait & UpdatePixelTrait) != 0)
5581 {
5582 if (((image->channels & WriteMaskChannel) != 0) &&
5583 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5584 return(MagickFalse);
5585 if (((image->channels & CompositeMaskChannel) != 0) &&
5586 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5587 return(MagickFalse);
5588 }
5589 if (nexus_info->authentic_pixel_cache != MagickFalse)
5590 {
5591 if (image->taint == MagickFalse)
5592 image->taint=MagickTrue;
5593 return(MagickTrue);
5594 }
5595 assert(cache_info->signature == MagickCoreSignature);
5596 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5597 if ((cache_info->metacontent_extent != 0) &&
5598 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5599 return(MagickFalse);
5600 if ((status != MagickFalse) && (image->taint == MagickFalse))
5601 image->taint=MagickTrue;
5602 return(status);
5603}
5604
5605/*
5606%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5607% %
5608% %
5609% %
5610+ S y n c A u t h e n t i c P i x e l C a c h e %
5611% %
5612% %
5613% %
5614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5615%
5616% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5617% or disk cache. The method returns MagickTrue if the pixel region is synced,
5618% otherwise MagickFalse.
5619%
5620% The format of the SyncAuthenticPixelsCache() method is:
5621%
5622% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5623% ExceptionInfo *exception)
5624%
5625% A description of each parameter follows:
5626%
5627% o image: the image.
5628%
5629% o exception: return any errors or warnings in this structure.
5630%
5631*/
5632static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5633 ExceptionInfo *exception)
5634{
5635 CacheInfo
5636 *magick_restrict cache_info;
5637
5638 const int
5639 id = GetOpenMPThreadId();
5640
5641 MagickBooleanType
5642 status;
5643
5644 assert(image != (Image *) NULL);
5645 assert(image->signature == MagickCoreSignature);
5646 assert(image->cache != (Cache) NULL);
5647 cache_info=(CacheInfo *) image->cache;
5648 assert(cache_info->signature == MagickCoreSignature);
5649 assert(id < (int) cache_info->number_threads);
5650 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5651 exception);
5652 return(status);
5653}
5654
5655/*
5656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5657% %
5658% %
5659% %
5660% S y n c A u t h e n t i c P i x e l s %
5661% %
5662% %
5663% %
5664%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5665%
5666% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5667% The method returns MagickTrue if the pixel region is flushed, otherwise
5668% MagickFalse.
5669%
5670% The format of the SyncAuthenticPixels() method is:
5671%
5672% MagickBooleanType SyncAuthenticPixels(Image *image,
5673% ExceptionInfo *exception)
5674%
5675% A description of each parameter follows:
5676%
5677% o image: the image.
5678%
5679% o exception: return any errors or warnings in this structure.
5680%
5681*/
5682MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5683 ExceptionInfo *exception)
5684{
5685 CacheInfo
5686 *magick_restrict cache_info;
5687
5688 const int
5689 id = GetOpenMPThreadId();
5690
5691 MagickBooleanType
5692 status;
5693
5694 assert(image != (Image *) NULL);
5695 assert(image->signature == MagickCoreSignature);
5696 assert(image->cache != (Cache) NULL);
5697 cache_info=(CacheInfo *) image->cache;
5698 assert(cache_info->signature == MagickCoreSignature);
5699 if (cache_info->methods.sync_authentic_pixels_handler != (SyncAuthenticPixelsHandler) NULL)
5700 {
5701 status=cache_info->methods.sync_authentic_pixels_handler(image,
5702 exception);
5703 return(status);
5704 }
5705 assert(id < (int) cache_info->number_threads);
5706 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5707 exception);
5708 return(status);
5709}
5710
5711/*
5712%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5713% %
5714% %
5715% %
5716+ S y n c I m a g e P i x e l C a c h e %
5717% %
5718% %
5719% %
5720%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5721%
5722% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5723% The method returns MagickTrue if the pixel region is flushed, otherwise
5724% MagickFalse.
5725%
5726% The format of the SyncImagePixelCache() method is:
5727%
5728% MagickBooleanType SyncImagePixelCache(Image *image,
5729% ExceptionInfo *exception)
5730%
5731% A description of each parameter follows:
5732%
5733% o image: the image.
5734%
5735% o exception: return any errors or warnings in this structure.
5736%
5737*/
5738MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5739 ExceptionInfo *exception)
5740{
5741 CacheInfo
5742 *magick_restrict cache_info;
5743
5744 assert(image != (Image *) NULL);
5745 assert(exception != (ExceptionInfo *) NULL);
5746 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5747 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5748}
5749
5750/*
5751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5752% %
5753% %
5754% %
5755+ 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 %
5756% %
5757% %
5758% %
5759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5760%
5761% WritePixelCacheMetacontent() writes the meta-content to the specified region
5762% of the pixel cache.
5763%
5764% The format of the WritePixelCacheMetacontent() method is:
5765%
5766% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5767% NexusInfo *nexus_info,ExceptionInfo *exception)
5768%
5769% A description of each parameter follows:
5770%
5771% o cache_info: the pixel cache.
5772%
5773% o nexus_info: the cache nexus to write the meta-content.
5774%
5775% o exception: return any errors or warnings in this structure.
5776%
5777*/
5778static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5779 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5780{
5781 MagickOffsetType
5782 count,
5783 offset;
5784
5785 MagickSizeType
5786 extent,
5787 length;
5788
5789 const unsigned char
5790 *magick_restrict p;
5791
5792 ssize_t
5793 y;
5794
5795 size_t
5796 rows;
5797
5798 if (cache_info->metacontent_extent == 0)
5799 return(MagickFalse);
5800 if (nexus_info->authentic_pixel_cache != MagickFalse)
5801 return(MagickTrue);
5802 if (nexus_info->metacontent == (unsigned char *) NULL)
5803 return(MagickFalse);
5804 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
5805 return(MagickFalse);
5806 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
5807 nexus_info->region.x;
5808 length=(MagickSizeType) nexus_info->region.width*
5809 cache_info->metacontent_extent;
5810 extent=(MagickSizeType) length*nexus_info->region.height;
5811 rows=nexus_info->region.height;
5812 y=0;
5813 p=(unsigned char *) nexus_info->metacontent;
5814 switch (cache_info->type)
5815 {
5816 case MemoryCache:
5817 case MapCache:
5818 {
5819 unsigned char
5820 *magick_restrict q;
5821
5822 /*
5823 Write associated pixels to memory.
5824 */
5825 if ((cache_info->columns == nexus_info->region.width) &&
5826 (extent == (MagickSizeType) ((size_t) extent)))
5827 {
5828 length=extent;
5829 rows=1UL;
5830 }
5831 q=(unsigned char *) cache_info->metacontent+offset*
5832 (MagickOffsetType) cache_info->metacontent_extent;
5833 for (y=0; y < (ssize_t) rows; y++)
5834 {
5835 (void) memcpy(q,p,(size_t) length);
5836 p+=(ptrdiff_t) nexus_info->region.width*cache_info->metacontent_extent;
5837 q+=(ptrdiff_t) cache_info->columns*cache_info->metacontent_extent;
5838 }
5839 break;
5840 }
5841 case DiskCache:
5842 {
5843 /*
5844 Write associated pixels to disk.
5845 */
5846 LockSemaphoreInfo(cache_info->file_semaphore);
5847 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5848 {
5849 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5850 cache_info->cache_filename);
5851 UnlockSemaphoreInfo(cache_info->file_semaphore);
5852 return(MagickFalse);
5853 }
5854 if ((cache_info->columns == nexus_info->region.width) &&
5855 (extent <= MagickMaxBufferExtent))
5856 {
5857 length=extent;
5858 rows=1UL;
5859 }
5860 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5861 for (y=0; y < (ssize_t) rows; y++)
5862 {
5863 count=WritePixelCacheRegion(cache_info,cache_info->offset+
5864 (MagickOffsetType) extent*(MagickOffsetType)
5865 cache_info->number_channels*(MagickOffsetType) sizeof(Quantum)+offset*
5866 (MagickOffsetType) cache_info->metacontent_extent,length,
5867 (const unsigned char *) p);
5868 if (count != (MagickOffsetType) length)
5869 break;
5870 p+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
5871 offset+=(MagickOffsetType) cache_info->columns;
5872 }
5873 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5874 (void) ClosePixelCacheOnDisk(cache_info);
5875 UnlockSemaphoreInfo(cache_info->file_semaphore);
5876 break;
5877 }
5878 case DistributedCache:
5879 {
5880 RectangleInfo
5881 region;
5882
5883 /*
5884 Write metacontent to distributed cache.
5885 */
5886 LockSemaphoreInfo(cache_info->file_semaphore);
5887 region=nexus_info->region;
5888 if ((cache_info->columns != nexus_info->region.width) ||
5889 (extent > MagickMaxBufferExtent))
5890 region.height=1UL;
5891 else
5892 {
5893 length=extent;
5894 rows=1UL;
5895 }
5896 for (y=0; y < (ssize_t) rows; y++)
5897 {
5898 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5899 cache_info->server_info,&region,length,(const unsigned char *) p);
5900 if (count != (MagickOffsetType) length)
5901 break;
5902 p+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
5903 region.y++;
5904 }
5905 UnlockSemaphoreInfo(cache_info->file_semaphore);
5906 break;
5907 }
5908 default:
5909 break;
5910 }
5911 if (y < (ssize_t) rows)
5912 {
5913 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5914 cache_info->cache_filename);
5915 return(MagickFalse);
5916 }
5917 if ((cache_info->debug != MagickFalse) &&
5918 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5919 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5920 "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
5921 nexus_info->region.width,(double) nexus_info->region.height,(double)
5922 nexus_info->region.x,(double) nexus_info->region.y);
5923 return(MagickTrue);
5924}
5925
5926/*
5927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5928% %
5929% %
5930% %
5931+ W r i t e C a c h e P i x e l s %
5932% %
5933% %
5934% %
5935%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5936%
5937% WritePixelCachePixels() writes image pixels to the specified region of the
5938% pixel cache.
5939%
5940% The format of the WritePixelCachePixels() method is:
5941%
5942% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5943% NexusInfo *nexus_info,ExceptionInfo *exception)
5944%
5945% A description of each parameter follows:
5946%
5947% o cache_info: the pixel cache.
5948%
5949% o nexus_info: the cache nexus to write the pixels.
5950%
5951% o exception: return any errors or warnings in this structure.
5952%
5953*/
5954static MagickBooleanType WritePixelCachePixels(
5955 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5956 ExceptionInfo *exception)
5957{
5958 MagickOffsetType
5959 count,
5960 offset;
5961
5962 MagickSizeType
5963 extent,
5964 length;
5965
5966 const Quantum
5967 *magick_restrict p;
5968
5969 ssize_t
5970 y;
5971
5972 size_t
5973 rows;
5974
5975 if (nexus_info->authentic_pixel_cache != MagickFalse)
5976 return(MagickTrue);
5977 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
5978 return(MagickFalse);
5979 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
5980 nexus_info->region.x;
5981 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5982 sizeof(Quantum);
5983 extent=length*nexus_info->region.height;
5984 rows=nexus_info->region.height;
5985 y=0;
5986 p=nexus_info->pixels;
5987 switch (cache_info->type)
5988 {
5989 case MemoryCache:
5990 case MapCache:
5991 {
5992 Quantum
5993 *magick_restrict q;
5994
5995 /*
5996 Write pixels to memory.
5997 */
5998 if ((cache_info->columns == nexus_info->region.width) &&
5999 (extent == (MagickSizeType) ((size_t) extent)))
6000 {
6001 length=extent;
6002 rows=1UL;
6003 }
6004 q=cache_info->pixels+(MagickOffsetType) cache_info->number_channels*
6005 offset;
6006 for (y=0; y < (ssize_t) rows; y++)
6007 {
6008 (void) memcpy(q,p,(size_t) length);
6009 p+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
6010 q+=(ptrdiff_t) cache_info->number_channels*cache_info->columns;
6011 }
6012 break;
6013 }
6014 case DiskCache:
6015 {
6016 /*
6017 Write pixels to disk.
6018 */
6019 LockSemaphoreInfo(cache_info->file_semaphore);
6020 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
6021 {
6022 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
6023 cache_info->cache_filename);
6024 UnlockSemaphoreInfo(cache_info->file_semaphore);
6025 return(MagickFalse);
6026 }
6027 if ((cache_info->columns == nexus_info->region.width) &&
6028 (extent <= MagickMaxBufferExtent))
6029 {
6030 length=extent;
6031 rows=1UL;
6032 }
6033 for (y=0; y < (ssize_t) rows; y++)
6034 {
6035 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
6036 (MagickOffsetType) cache_info->number_channels*(MagickOffsetType)
6037 sizeof(*p),length,(const unsigned char *) p);
6038 if (count != (MagickOffsetType) length)
6039 break;
6040 p+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
6041 offset+=(MagickOffsetType) cache_info->columns;
6042 }
6043 if (IsFileDescriptorLimitExceeded() != MagickFalse)
6044 (void) ClosePixelCacheOnDisk(cache_info);
6045 UnlockSemaphoreInfo(cache_info->file_semaphore);
6046 break;
6047 }
6048 case DistributedCache:
6049 {
6050 RectangleInfo
6051 region;
6052
6053 /*
6054 Write pixels to distributed cache.
6055 */
6056 LockSemaphoreInfo(cache_info->file_semaphore);
6057 region=nexus_info->region;
6058 if ((cache_info->columns != nexus_info->region.width) ||
6059 (extent > MagickMaxBufferExtent))
6060 region.height=1UL;
6061 else
6062 {
6063 length=extent;
6064 rows=1UL;
6065 }
6066 for (y=0; y < (ssize_t) rows; y++)
6067 {
6068 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
6069 cache_info->server_info,&region,length,(const unsigned char *) p);
6070 if (count != (MagickOffsetType) length)
6071 break;
6072 p+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
6073 region.y++;
6074 }
6075 UnlockSemaphoreInfo(cache_info->file_semaphore);
6076 break;
6077 }
6078 default:
6079 break;
6080 }
6081 if (y < (ssize_t) rows)
6082 {
6083 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
6084 cache_info->cache_filename);
6085 return(MagickFalse);
6086 }
6087 if ((cache_info->debug != MagickFalse) &&
6088 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
6089 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
6090 "%s[%.17gx%.17g%+.20g%+.20g]",cache_info->filename,(double)
6091 nexus_info->region.width,(double) nexus_info->region.height,(double)
6092 nexus_info->region.x,(double) nexus_info->region.y);
6093 return(MagickTrue);
6094}