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