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