MagickCore 7.1.2
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
cache.c
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC AAA CCCC H H EEEEE %
7% C A A C H H E %
8% C AAAAA C HHHHH EEE %
9% C A A C H H E %
10% CCCC A A CCCC H H EEEEE %
11% %
12% %
13% MagickCore Pixel Cache Methods %
14% %
15% Software Design %
16% Cristy %
17% July 1999 %
18% %
19% %
20% Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
21% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% https://imagemagick.org/license/ %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "MagickCore/studio.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/colorspace-private.h"
50#include "MagickCore/composite-private.h"
51#include "MagickCore/distribute-cache-private.h"
52#include "MagickCore/exception.h"
53#include "MagickCore/exception-private.h"
54#include "MagickCore/geometry.h"
55#include "MagickCore/list.h"
56#include "MagickCore/log.h"
57#include "MagickCore/magick.h"
58#include "MagickCore/memory_.h"
59#include "MagickCore/memory-private.h"
60#include "MagickCore/nt-base-private.h"
61#include "MagickCore/option.h"
62#include "MagickCore/pixel.h"
63#include "MagickCore/pixel-accessor.h"
64#include "MagickCore/pixel-private.h"
65#include "MagickCore/policy.h"
66#include "MagickCore/quantum.h"
67#include "MagickCore/random_.h"
68#include "MagickCore/registry.h"
69#include "MagickCore/resource_.h"
70#include "MagickCore/semaphore.h"
71#include "MagickCore/splay-tree.h"
72#include "MagickCore/string_.h"
73#include "MagickCore/string-private.h"
74#include "MagickCore/timer-private.h"
75#include "MagickCore/thread-private.h"
76#include "MagickCore/utility.h"
77#include "MagickCore/utility-private.h"
78#if defined(MAGICKCORE_HAVE_SYS_LOADAVG_H)
79# include <sys/loadavg.h>
80#endif
81#if defined(MAGICKCORE_ZLIB_DELEGATE)
82# include "zlib.h"
83#endif
84
85/*
86 Define declarations.
87*/
88#define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
89#define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
90 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
91
92/*
93 Typedef declarations.
94*/
95typedef struct _MagickModulo
96{
97 ssize_t
98 quotient,
99 remainder;
100} MagickModulo;
101
102/*
103 Forward declarations.
104*/
105#if defined(__cplusplus) || defined(c_plusplus)
106extern "C" {
107#endif
108
109static Cache
110 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
111 magick_hot_spot;
112
113static const Quantum
114 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
115 const ssize_t,const size_t,const size_t,ExceptionInfo *),
116 *GetVirtualPixelsCache(const Image *);
117
118static const void
119 *GetVirtualMetacontentFromCache(const Image *);
120
121static MagickBooleanType
122 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
123 ExceptionInfo *),
124 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
125 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
126 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
127 OpenPixelCacheOnDisk(CacheInfo *,const MapMode),
128 ReadPixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict,
129 ExceptionInfo *),
130 ReadPixelCacheMetacontent(CacheInfo *magick_restrict,
131 NexusInfo *magick_restrict,ExceptionInfo *),
132 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
133 WritePixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict,
134 ExceptionInfo *),
135 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *magick_restrict,
136 ExceptionInfo *);
137
138static Quantum
139 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
140 const size_t,ExceptionInfo *),
141 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
143 *SetPixelCacheNexusPixels(const CacheInfo *magick_restrict,const MapMode,
144 const ssize_t,const ssize_t,const size_t,const size_t,
145 const MagickBooleanType,NexusInfo *magick_restrict,ExceptionInfo *)
146 magick_hot_spot;
147
148#if defined(MAGICKCORE_OPENCL_SUPPORT)
149static void
150 CopyOpenCLBuffer(CacheInfo *magick_restrict);
151#endif
152
153#if defined(__cplusplus) || defined(c_plusplus)
154}
155#endif
156
157/*
158 Global declarations.
159*/
160static SemaphoreInfo
161 *cache_semaphore = (SemaphoreInfo *) NULL;
162
163static ssize_t
164 cache_anonymous_memory = (-1);
165
166/*
167%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168% %
169% %
170% %
171+ A c q u i r e P i x e l C a c h e %
172% %
173% %
174% %
175%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176%
177% AcquirePixelCache() acquires a pixel cache.
178%
179% The format of the AcquirePixelCache() method is:
180%
181% Cache AcquirePixelCache(const size_t number_threads)
182%
183% A description of each parameter follows:
184%
185% o number_threads: the number of nexus threads.
186%
187*/
188MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
189{
190 CacheInfo
191 *magick_restrict cache_info;
192
193 char
194 *value;
195
196 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
197 if (cache_info == (CacheInfo *) NULL)
198 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
199 (void) memset(cache_info,0,sizeof(*cache_info));
200 cache_info->type=UndefinedCache;
201 cache_info->mode=IOMode;
202 cache_info->disk_mode=IOMode;
203 cache_info->colorspace=sRGBColorspace;
204 cache_info->file=(-1);
205 cache_info->id=GetMagickThreadId();
206 cache_info->number_threads=number_threads;
207 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
208 cache_info->number_threads=GetOpenMPMaximumThreads();
209 if (cache_info->number_threads == 0)
210 cache_info->number_threads=1;
211 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
212 value=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
213 if (value != (const char *) NULL)
214 {
215 cache_info->synchronize=IsStringTrue(value);
216 value=DestroyString(value);
217 }
218 value=GetPolicyValue("cache:synchronize");
219 if (value != (const char *) NULL)
220 {
221 cache_info->synchronize=IsStringTrue(value);
222 value=DestroyString(value);
223 }
224 cache_info->width_limit=MagickMin(GetMagickResourceLimit(WidthResource),
225 (MagickSizeType) MAGICK_SSIZE_MAX);
226 cache_info->height_limit=MagickMin(GetMagickResourceLimit(HeightResource),
227 (MagickSizeType) MAGICK_SSIZE_MAX);
228 cache_info->semaphore=AcquireSemaphoreInfo();
229 cache_info->reference_count=1;
230 cache_info->file_semaphore=AcquireSemaphoreInfo();
231 cache_info->debug=(GetLogEventMask() & CacheEvent) != 0 ? MagickTrue :
232 MagickFalse;
233 cache_info->signature=MagickCoreSignature;
234 return((Cache ) cache_info);
235}
236
237/*
238%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239% %
240% %
241% %
242% A c q u i r e P i x e l C a c h e N e x u s %
243% %
244% %
245% %
246%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247%
248% AcquirePixelCacheNexus() allocates the NexusInfo structure.
249%
250% The format of the AcquirePixelCacheNexus method is:
251%
252% NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
253%
254% A description of each parameter follows:
255%
256% o number_threads: the number of nexus threads.
257%
258*/
259MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
260{
261 NexusInfo
262 **magick_restrict nexus_info;
263
264 ssize_t
265 i;
266
267 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(2*
268 number_threads,sizeof(*nexus_info)));
269 if (nexus_info == (NexusInfo **) NULL)
270 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
271 *nexus_info=(NexusInfo *) AcquireQuantumMemory(number_threads,
272 2*sizeof(**nexus_info));
273 if (*nexus_info == (NexusInfo *) NULL)
274 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
275 (void) memset(*nexus_info,0,2*number_threads*sizeof(**nexus_info));
276 for (i=0; i < (ssize_t) (2*number_threads); i++)
277 {
278 nexus_info[i]=(*nexus_info+i);
279 if (i < (ssize_t) number_threads)
280 nexus_info[i]->virtual_nexus=(*nexus_info+number_threads+i);
281 nexus_info[i]->signature=MagickCoreSignature;
282 }
283 return(nexus_info);
284}
285
286/*
287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288% %
289% %
290% %
291% A c q u i r e P i x e l C a c h e P i x e l s %
292% %
293% %
294% %
295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296%
297% AcquirePixelCachePixels() returns the pixels associated with the specified
298% image.
299%
300% The format of the AcquirePixelCachePixels() method is:
301%
302% void *AcquirePixelCachePixels(const Image *image,size_t *length,
303% ExceptionInfo *exception)
304%
305% A description of each parameter follows:
306%
307% o image: the image.
308%
309% o length: the pixel cache length.
310%
311% o exception: return any errors or warnings in this structure.
312%
313*/
314MagickExport void *AcquirePixelCachePixels(const Image *image,size_t *length,
315 ExceptionInfo *exception)
316{
317 CacheInfo
318 *magick_restrict cache_info;
319
320 assert(image != (const Image *) NULL);
321 assert(image->signature == MagickCoreSignature);
322 assert(exception != (ExceptionInfo *) NULL);
323 assert(exception->signature == MagickCoreSignature);
324 assert(image->cache != (Cache) NULL);
325 (void) exception;
326 cache_info=(CacheInfo *) image->cache;
327 assert(cache_info->signature == MagickCoreSignature);
328 *length=0;
329 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
330 return((void *) NULL);
331 *length=(size_t) cache_info->length;
332 return(cache_info->pixels);
333}
334
335/*
336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337% %
338% %
339% %
340+ C a c h e C o m p o n e n t G e n e s i s %
341% %
342% %
343% %
344%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345%
346% CacheComponentGenesis() instantiates the cache component.
347%
348% The format of the CacheComponentGenesis method is:
349%
350% MagickBooleanType CacheComponentGenesis(void)
351%
352*/
353MagickPrivate MagickBooleanType CacheComponentGenesis(void)
354{
355 if (cache_semaphore == (SemaphoreInfo *) NULL)
356 cache_semaphore=AcquireSemaphoreInfo();
357 return(MagickTrue);
358}
359
360/*
361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362% %
363% %
364% %
365+ C a c h e C o m p o n e n t T e r m i n u s %
366% %
367% %
368% %
369%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370%
371% CacheComponentTerminus() destroys the cache component.
372%
373% The format of the CacheComponentTerminus() method is:
374%
375% CacheComponentTerminus(void)
376%
377*/
378MagickPrivate void CacheComponentTerminus(void)
379{
380 if (cache_semaphore == (SemaphoreInfo *) NULL)
381 ActivateSemaphoreInfo(&cache_semaphore);
382 /* no op-- nothing to destroy */
383 RelinquishSemaphoreInfo(&cache_semaphore);
384}
385
386/*
387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388% %
389% %
390% %
391+ C l i p P i x e l C a c h e N e x u s %
392% %
393% %
394% %
395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396%
397% ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
398% mask. The method returns MagickTrue if the pixel region is clipped,
399% otherwise MagickFalse.
400%
401% The format of the ClipPixelCacheNexus() method is:
402%
403% MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
404% ExceptionInfo *exception)
405%
406% A description of each parameter follows:
407%
408% o image: the image.
409%
410% o nexus_info: the cache nexus to clip.
411%
412% o exception: return any errors or warnings in this structure.
413%
414*/
415static MagickBooleanType ClipPixelCacheNexus(Image *image,
416 NexusInfo *nexus_info,ExceptionInfo *exception)
417{
418 CacheInfo
419 *magick_restrict cache_info;
420
421 Quantum
422 *magick_restrict p,
423 *magick_restrict q;
424
425 ssize_t
426 y;
427
428 /*
429 Apply clip mask.
430 */
431 if (IsEventLogging() != MagickFalse)
432 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
433 if ((image->channels & WriteMaskChannel) == 0)
434 return(MagickTrue);
435 if ((nexus_info->region.width == 0) || (nexus_info->region.height == 0))
436 return(MagickTrue);
437 cache_info=(CacheInfo *) image->cache;
438 if (cache_info == (CacheInfo *) NULL)
439 return(MagickFalse);
440 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
441 nexus_info->region.width,nexus_info->region.height,
442 nexus_info->virtual_nexus,exception);
443 q=nexus_info->pixels;
444 if ((p == (Quantum *) NULL) || (q == (Quantum *) NULL))
445 return(MagickFalse);
446 for (y=0; y < (ssize_t) nexus_info->region.height; y++)
447 {
448 ssize_t
449 x;
450
451 for (x=0; x < (ssize_t) nexus_info->region.width; x++)
452 {
453 double
454 mask_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{
505 CacheInfo
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{
549 CacheInfo
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
694 NexusInfo
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{
938 CacheInfo
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{
2768 MagickModulo
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 {
2987 MagickModulo
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 != (GetVirtualPixelsHandler) NULL)
3268 return(cache_info->methods.get_virtual_pixels_handler(image));
3269 assert(id < (int) cache_info->number_threads);
3270 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3271}
3272
3273/*
3274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3275% %
3276% %
3277% %
3278% G e t V i r t u a l P i x e l s %
3279% %
3280% %
3281% %
3282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3283%
3284% GetVirtualPixels() returns an immutable pixel region. If the
3285% region is successfully accessed, a pointer to it is returned, otherwise
3286% NULL is returned. The returned pointer may point to a temporary working
3287% copy of the pixels or it may point to the original pixels in memory.
3288% Performance is maximized if the selected region is part of one row, or one
3289% or more full rows, since there is opportunity to access the pixels in-place
3290% (without a copy) if the image is in memory, or in a memory-mapped file. The
3291% returned pointer must *never* be deallocated by the user.
3292%
3293% Pixels accessed via the returned pointer represent a simple array of type
3294% Quantum. If the image type is CMYK or the storage class is PseudoClass,
3295% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3296% access the meta-content (of type void) corresponding to the
3297% region.
3298%
3299% If you plan to modify the pixels, use GetAuthenticPixels() instead.
3300%
3301% Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3302% safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3303% GetCacheViewAuthenticPixels() instead.
3304%
3305% The format of the GetVirtualPixels() method is:
3306%
3307% const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3308% const ssize_t y,const size_t columns,const size_t rows,
3309% ExceptionInfo *exception)
3310%
3311% A description of each parameter follows:
3312%
3313% o image: the image.
3314%
3315% o x,y,columns,rows: These values define the perimeter of a region of
3316% pixels.
3317%
3318% o exception: return any errors or warnings in this structure.
3319%
3320*/
3321MagickExport const Quantum *GetVirtualPixels(const Image *image,
3322 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3323 ExceptionInfo *exception)
3324{
3325 CacheInfo
3326 *magick_restrict cache_info;
3327
3328 const int
3329 id = GetOpenMPThreadId();
3330
3331 const Quantum
3332 *magick_restrict p;
3333
3334 assert(image != (const Image *) NULL);
3335 assert(image->signature == MagickCoreSignature);
3336 assert(image->cache != (Cache) NULL);
3337 cache_info=(CacheInfo *) image->cache;
3338 assert(cache_info->signature == MagickCoreSignature);
3339 if (cache_info->methods.get_virtual_pixel_handler !=
3340 (GetVirtualPixelHandler) NULL)
3341 return(cache_info->methods.get_virtual_pixel_handler(image,
3342 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3343 assert(id < (int) cache_info->number_threads);
3344 p=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3345 columns,rows,cache_info->nexus_info[id],exception);
3346 return(p);
3347}
3348
3349/*
3350%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3351% %
3352% %
3353% %
3354+ 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 %
3355% %
3356% %
3357% %
3358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3359%
3360% GetVirtualPixelsCache() returns the pixels associated corresponding with the
3361% last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3362%
3363% The format of the GetVirtualPixelsCache() method is:
3364%
3365% Quantum *GetVirtualPixelsCache(const Image *image)
3366%
3367% A description of each parameter follows:
3368%
3369% o image: the image.
3370%
3371*/
3372static const Quantum *GetVirtualPixelsCache(const Image *image)
3373{
3374 CacheInfo
3375 *magick_restrict cache_info;
3376
3377 const int
3378 id = GetOpenMPThreadId();
3379
3380 assert(image != (const Image *) NULL);
3381 assert(image->signature == MagickCoreSignature);
3382 assert(image->cache != (Cache) NULL);
3383 cache_info=(CacheInfo *) image->cache;
3384 assert(cache_info->signature == MagickCoreSignature);
3385 assert(id < (int) cache_info->number_threads);
3386 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3387}
3388
3389/*
3390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3391% %
3392% %
3393% %
3394+ G e t V i r t u a l P i x e l s N e x u s %
3395% %
3396% %
3397% %
3398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3399%
3400% GetVirtualPixelsNexus() returns the pixels associated with the specified
3401% cache nexus.
3402%
3403% The format of the GetVirtualPixelsNexus() method is:
3404%
3405% const Quantum *GetVirtualPixelsNexus(const Cache cache,
3406% NexusInfo *nexus_info)
3407%
3408% A description of each parameter follows:
3409%
3410% o cache: the pixel cache.
3411%
3412% o nexus_info: the cache nexus to return the colormap pixels.
3413%
3414*/
3415MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3416 NexusInfo *magick_restrict nexus_info)
3417{
3418 CacheInfo
3419 *magick_restrict cache_info;
3420
3421 assert(cache != (Cache) NULL);
3422 cache_info=(CacheInfo *) cache;
3423 assert(cache_info->signature == MagickCoreSignature);
3424 if (cache_info->storage_class == UndefinedClass)
3425 return((Quantum *) NULL);
3426 return((const Quantum *) nexus_info->pixels);
3427}
3428
3429/*
3430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3431% %
3432% %
3433% %
3434+ M a s k P i x e l C a c h e N e x u s %
3435% %
3436% %
3437% %
3438%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3439%
3440% MaskPixelCacheNexus() masks the cache nexus as defined by the composite mask.
3441% The method returns MagickTrue if the pixel region is masked, otherwise
3442% MagickFalse.
3443%
3444% The format of the MaskPixelCacheNexus() method is:
3445%
3446% MagickBooleanType MaskPixelCacheNexus(Image *image,
3447% NexusInfo *nexus_info,ExceptionInfo *exception)
3448%
3449% A description of each parameter follows:
3450%
3451% o image: the image.
3452%
3453% o nexus_info: the cache nexus to clip.
3454%
3455% o exception: return any errors or warnings in this structure.
3456%
3457*/
3458
3459static inline Quantum ApplyPixelCompositeMask(const Quantum p,
3460 const MagickRealType alpha,const Quantum q,const MagickRealType beta)
3461{
3462 double
3463 gamma;
3464
3465 if (fabs((double) (alpha-(double) TransparentAlpha)) < MagickEpsilon)
3466 return(q);
3467 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3468 gamma=MagickSafeReciprocal(gamma);
3469 return(ClampToQuantum(gamma*MagickOver_((double) p,alpha,(double) q,beta)));
3470}
3471
3472static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3473 ExceptionInfo *exception)
3474{
3475 CacheInfo
3476 *magick_restrict cache_info;
3477
3478 Quantum
3479 *magick_restrict p,
3480 *magick_restrict q;
3481
3482 ssize_t
3483 y;
3484
3485 /*
3486 Apply composite mask.
3487 */
3488 if (IsEventLogging() != MagickFalse)
3489 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3490 if ((image->channels & CompositeMaskChannel) == 0)
3491 return(MagickTrue);
3492 if ((nexus_info->region.width == 0) || (nexus_info->region.height == 0))
3493 return(MagickTrue);
3494 cache_info=(CacheInfo *) image->cache;
3495 if (cache_info == (Cache) NULL)
3496 return(MagickFalse);
3497 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3498 nexus_info->region.width,nexus_info->region.height,
3499 nexus_info->virtual_nexus,exception);
3500 q=nexus_info->pixels;
3501 if ((p == (Quantum *) NULL) || (q == (Quantum *) NULL))
3502 return(MagickFalse);
3503 for (y=0; y < (ssize_t) nexus_info->region.height; y++)
3504 {
3505 ssize_t
3506 x;
3507
3508 for (x=0; x < (ssize_t) nexus_info->region.width; x++)
3509 {
3510 double
3511 alpha;
3512
3513 ssize_t
3514 i;
3515
3516 alpha=(double) GetPixelCompositeMask(image,p);
3517 for (i=0; i < (ssize_t) image->number_channels; i++)
3518 {
3519 PixelChannel channel = GetPixelChannelChannel(image,i);
3520 PixelTrait traits = GetPixelChannelTraits(image,channel);
3521 if ((traits & UpdatePixelTrait) == 0)
3522 continue;
3523 q[i]=ApplyPixelCompositeMask(q[i],alpha,p[i],GetPixelAlpha(image,p));
3524 }
3525 p+=(ptrdiff_t) GetPixelChannels(image);
3526 q+=(ptrdiff_t) GetPixelChannels(image);
3527 }
3528 }
3529 return(MagickTrue);
3530}
3531
3532/*
3533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3534% %
3535% %
3536% %
3537+ O p e n P i x e l C a c h e %
3538% %
3539% %
3540% %
3541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3542%
3543% OpenPixelCache() allocates the pixel cache. This includes defining the cache
3544% dimensions, allocating space for the image pixels and optionally the
3545% metacontent, and memory mapping the cache if it is disk based. The cache
3546% nexus array is initialized as well.
3547%
3548% The format of the OpenPixelCache() method is:
3549%
3550% MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3551% ExceptionInfo *exception)
3552%
3553% A description of each parameter follows:
3554%
3555% o image: the image.
3556%
3557% o mode: ReadMode, WriteMode, or IOMode.
3558%
3559% o exception: return any errors or warnings in this structure.
3560%
3561*/
3562
3563static inline MagickBooleanType CacheOverflowSanityCheckGetSize(
3564 const MagickSizeType count,const size_t quantum,MagickSizeType *const extent)
3565{
3566 MagickSizeType
3567 length;
3568
3569 if ((count == 0) || (quantum == 0))
3570 return(MagickTrue);
3571 length=count*quantum;
3572 if (quantum != (length/count))
3573 {
3574 errno=ENOMEM;
3575 return(MagickTrue);
3576 }
3577 if (extent != NULL)
3578 *extent=length;
3579 return(MagickFalse);
3580}
3581
3582static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3583 const MapMode mode)
3584{
3585 int
3586 file;
3587
3588 /*
3589 Open pixel cache on disk.
3590 */
3591 if ((cache_info->file != -1) && (cache_info->disk_mode == mode))
3592 return(MagickTrue); /* cache already open and in the proper mode */
3593 if (*cache_info->cache_filename == '\0')
3594 file=AcquireUniqueFileResource(cache_info->cache_filename);
3595 else
3596 switch (mode)
3597 {
3598 case ReadMode:
3599 {
3600 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3601 break;
3602 }
3603 case WriteMode:
3604 {
3605 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3606 O_BINARY | O_EXCL,S_MODE);
3607 if (file == -1)
3608 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3609 break;
3610 }
3611 case IOMode:
3612 default:
3613 {
3614 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3615 O_EXCL,S_MODE);
3616 if (file == -1)
3617 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3618 break;
3619 }
3620 }
3621 if (file == -1)
3622 return(MagickFalse);
3623 (void) AcquireMagickResource(FileResource,1);
3624 if (cache_info->file != -1)
3625 (void) ClosePixelCacheOnDisk(cache_info);
3626 cache_info->file=file;
3627 cache_info->disk_mode=mode;
3628 return(MagickTrue);
3629}
3630
3631static inline MagickOffsetType WritePixelCacheRegion(
3632 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3633 const MagickSizeType length,const unsigned char *magick_restrict buffer)
3634{
3635 MagickOffsetType
3636 i;
3637
3638 ssize_t
3639 count = 0;
3640
3641#if !defined(MAGICKCORE_HAVE_PWRITE)
3642 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3643 return((MagickOffsetType) -1);
3644#endif
3645 for (i=0; i < (MagickOffsetType) length; i+=count)
3646 {
3647#if !defined(MAGICKCORE_HAVE_PWRITE)
3648 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-
3649 (MagickSizeType) i,MagickMaxBufferExtent));
3650#else
3651 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-
3652 (MagickSizeType) i,MagickMaxBufferExtent),offset+i);
3653#endif
3654 if (count <= 0)
3655 {
3656 count=0;
3657 if (errno != EINTR)
3658 break;
3659 }
3660 }
3661 return(i);
3662}
3663
3664static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3665{
3666 CacheInfo
3667 *magick_restrict cache_info;
3668
3669 MagickOffsetType
3670 offset;
3671
3672 cache_info=(CacheInfo *) image->cache;
3673 if (cache_info->debug != MagickFalse)
3674 {
3675 char
3676 format[MagickPathExtent],
3677 message[MagickPathExtent];
3678
3679 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3680 (void) FormatLocaleString(message,MagickPathExtent,
3681 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3682 cache_info->cache_filename,cache_info->file,format);
3683 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3684 }
3685 if (length != (MagickSizeType) ((MagickOffsetType) length))
3686 return(MagickFalse);
3687 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3688 if (offset < 0)
3689 return(MagickFalse);
3690 if ((MagickSizeType) offset < length)
3691 {
3692 MagickOffsetType
3693 count,
3694 extent;
3695
3696 extent=(MagickOffsetType) length-1;
3697 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3698 "");
3699 if (count != 1)
3700 return(MagickFalse);
3701#if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3702 if (cache_info->synchronize != MagickFalse)
3703 if (posix_fallocate(cache_info->file,offset+1,extent-offset) != 0)
3704 return(MagickFalse);
3705#endif
3706 }
3707 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3708 if (offset < 0)
3709 return(MagickFalse);
3710 return(MagickTrue);
3711}
3712
3713static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3714 ExceptionInfo *exception)
3715{
3716 CacheInfo
3717 *magick_restrict cache_info,
3718 source_info;
3719
3720 char
3721 format[MagickPathExtent],
3722 message[MagickPathExtent];
3723
3724 const char
3725 *hosts,
3726 *type;
3727
3728 MagickBooleanType
3729 status;
3730
3731 MagickSizeType
3732 length = 0,
3733 number_pixels;
3734
3735 size_t
3736 columns,
3737 packet_size;
3738
3739 assert(image != (const Image *) NULL);
3740 assert(image->signature == MagickCoreSignature);
3741 assert(image->cache != (Cache) NULL);
3742 if (IsEventLogging() != MagickFalse)
3743 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3744 if (cache_anonymous_memory < 0)
3745 {
3746 char
3747 *value;
3748
3749 /*
3750 Does the security policy require anonymous mapping for pixel cache?
3751 */
3752 cache_anonymous_memory=0;
3753 value=GetPolicyValue("pixel-cache-memory");
3754 if (value == (char *) NULL)
3755 value=GetPolicyValue("cache:memory-map");
3756 if (LocaleCompare(value,"anonymous") == 0)
3757 {
3758#if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3759 cache_anonymous_memory=1;
3760#else
3761 (void) ThrowMagickException(exception,GetMagickModule(),
3762 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3763 "`%s' (policy requires anonymous memory mapping)",image->filename);
3764#endif
3765 }
3766 value=DestroyString(value);
3767 }
3768 if ((image->columns == 0) || (image->rows == 0))
3769 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3770 cache_info=(CacheInfo *) image->cache;
3771 assert(cache_info->signature == MagickCoreSignature);
3772 if (((MagickSizeType) image->columns > cache_info->width_limit) ||
3773 ((MagickSizeType) image->rows > cache_info->height_limit))
3774 {
3775 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
3776 "WidthOrHeightExceedsLimit","`%s' (%.20gx%.20g) > (%.20gx%.20g)",
3777 image->filename, (double) image->columns, (double) image->rows,
3778 (double) cache_info->width_limit,(double) cache_info->height_limit);
3779 return(MagickFalse);
3780 }
3781 if (GetMagickResourceLimit(ListLengthResource) != MagickResourceInfinity)
3782 {
3783 length=GetImageListLength(image);
3784 if (AcquireMagickResource(ListLengthResource,length) == MagickFalse)
3785 ThrowBinaryException(ResourceLimitError,"ListLengthExceedsLimit",
3786 image->filename);
3787 }
3788 source_info=(*cache_info);
3789 source_info.file=(-1);
3790 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3791 image->filename,(double) image->scene);
3792 cache_info->storage_class=image->storage_class;
3793 cache_info->colorspace=image->colorspace;
3794 cache_info->alpha_trait=image->alpha_trait;
3795 cache_info->channels=image->channels;
3796 cache_info->rows=image->rows;
3797 cache_info->columns=image->columns;
3798 status=ResetPixelChannelMap(image,exception);
3799 if (status == MagickFalse)
3800 return(MagickFalse);
3801 cache_info->number_channels=GetPixelChannels(image);
3802 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3803 sizeof(*image->channel_map));
3804 cache_info->metacontent_extent=image->metacontent_extent;
3805 cache_info->mode=mode;
3806 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3807 packet_size=MagickMax(cache_info->number_channels,1)*sizeof(Quantum);
3808 if (image->metacontent_extent != 0)
3809 packet_size+=cache_info->metacontent_extent;
3810 if (CacheOverflowSanityCheckGetSize(number_pixels,packet_size,&length) != MagickFalse)
3811 {
3812 cache_info->storage_class=UndefinedClass;
3813 cache_info->length=0;
3814 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3815 image->filename);
3816 }
3817 columns=(size_t) (length/cache_info->rows/packet_size);
3818 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3819 ((ssize_t) cache_info->rows < 0))
3820 {
3821 cache_info->storage_class=UndefinedClass;
3822 cache_info->length=0;
3823 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3824 image->filename);
3825 }
3826 cache_info->length=length;
3827 if (image->ping != MagickFalse)
3828 {
3829 cache_info->type=PingCache;
3830 return(MagickTrue);
3831 }
3832 status=AcquireMagickResource(AreaResource,(MagickSizeType)
3833 cache_info->columns*cache_info->rows);
3834 if (cache_info->mode == PersistMode)
3835 status=MagickFalse;
3836 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3837 cache_info->metacontent_extent);
3838 if ((status != MagickFalse) &&
3839 (length == (MagickSizeType) ((size_t) length)) &&
3840 ((cache_info->type == UndefinedCache) ||
3841 (cache_info->type == MemoryCache)))
3842 {
3843 status=AcquireMagickResource(MemoryResource,cache_info->length);
3844 if (status != MagickFalse)
3845 {
3846 status=MagickTrue;
3847 if (cache_anonymous_memory <= 0)
3848 {
3849 cache_info->mapped=MagickFalse;
3850 cache_info->pixels=(Quantum *) MagickAssumeAligned(
3851 AcquireAlignedMemory(1,(size_t) cache_info->length));
3852 }
3853 else
3854 {
3855 cache_info->mapped=MagickTrue;
3856 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3857 cache_info->length);
3858 }
3859 if (cache_info->pixels == (Quantum *) NULL)
3860 {
3861 cache_info->mapped=source_info.mapped;
3862 cache_info->pixels=source_info.pixels;
3863 }
3864 else
3865 {
3866 /*
3867 Create memory pixel cache.
3868 */
3869 cache_info->type=MemoryCache;
3870 cache_info->metacontent=(void *) NULL;
3871 if (cache_info->metacontent_extent != 0)
3872 cache_info->metacontent=(void *) (cache_info->pixels+
3873 cache_info->number_channels*number_pixels);
3874 if ((source_info.storage_class != UndefinedClass) &&
3875 (mode != ReadMode))
3876 {
3877 status=ClonePixelCacheRepository(cache_info,&source_info,
3878 exception);
3879 RelinquishPixelCachePixels(&source_info);
3880 }
3881 if (cache_info->debug != MagickFalse)
3882 {
3883 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3884 MagickPathExtent,format);
3885 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3886 cache_info->type);
3887 (void) FormatLocaleString(message,MagickPathExtent,
3888 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3889 cache_info->filename,cache_info->mapped != MagickFalse ?
3890 "Anonymous" : "Heap",type,(double) cache_info->columns,
3891 (double) cache_info->rows,(double)
3892 cache_info->number_channels,format);
3893 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3894 message);
3895 }
3896 cache_info->storage_class=image->storage_class;
3897 if (status == 0)
3898 {
3899 if ((source_info.storage_class != UndefinedClass) &&
3900 (mode != ReadMode))
3901 RelinquishPixelCachePixels(&source_info);
3902 cache_info->type=UndefinedCache;
3903 return(MagickFalse);
3904 }
3905 return(MagickTrue);
3906 }
3907 }
3908 }
3909 status=AcquireMagickResource(DiskResource,cache_info->length);
3910 hosts=(const char *) GetImageRegistry(StringRegistryType,"cache:hosts",
3911 exception);
3912 if ((status == MagickFalse) && (hosts != (const char *) NULL))
3913 {
3914 DistributeCacheInfo
3915 *server_info;
3916
3917 /*
3918 Distribute the pixel cache to a remote server.
3919 */
3920 server_info=AcquireDistributeCacheInfo(exception);
3921 if (server_info != (DistributeCacheInfo *) NULL)
3922 {
3923 status=OpenDistributePixelCache(server_info,image);
3924 if (status == MagickFalse)
3925 {
3926 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3927 GetDistributeCacheHostname(server_info));
3928 server_info=DestroyDistributeCacheInfo(server_info);
3929 }
3930 else
3931 {
3932 /*
3933 Create a distributed pixel cache.
3934 */
3935 status=MagickTrue;
3936 cache_info->type=DistributedCache;
3937 cache_info->server_info=server_info;
3938 (void) FormatLocaleString(cache_info->cache_filename,
3939 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3940 (DistributeCacheInfo *) cache_info->server_info),
3941 GetDistributeCachePort((DistributeCacheInfo *)
3942 cache_info->server_info));
3943 if ((source_info.storage_class != UndefinedClass) &&
3944 (mode != ReadMode))
3945 {
3946 status=ClonePixelCacheRepository(cache_info,&source_info,
3947 exception);
3948 RelinquishPixelCachePixels(&source_info);
3949 }
3950 if (cache_info->debug != MagickFalse)
3951 {
3952 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3953 MagickPathExtent,format);
3954 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3955 cache_info->type);
3956 (void) FormatLocaleString(message,MagickPathExtent,
3957 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3958 cache_info->filename,cache_info->cache_filename,
3959 GetDistributeCacheFile((DistributeCacheInfo *)
3960 cache_info->server_info),type,(double) cache_info->columns,
3961 (double) cache_info->rows,(double)
3962 cache_info->number_channels,format);
3963 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3964 message);
3965 }
3966 if (status == 0)
3967 {
3968 if ((source_info.storage_class != UndefinedClass) &&
3969 (mode != ReadMode))
3970 RelinquishPixelCachePixels(&source_info);
3971 cache_info->type=UndefinedCache;
3972 return(MagickFalse);
3973 }
3974 return(MagickTrue);
3975 }
3976 }
3977 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3978 RelinquishPixelCachePixels(&source_info);
3979 cache_info->type=UndefinedCache;
3980 (void) memset(image->channel_map,0,MaxPixelChannels*
3981 sizeof(*image->channel_map));
3982 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3983 "CacheResourcesExhausted","`%s'",image->filename);
3984 return(MagickFalse);
3985 }
3986 /*
3987 Create pixel cache on disk.
3988 */
3989 if (status == MagickFalse)
3990 {
3991 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3992 RelinquishPixelCachePixels(&source_info);
3993 cache_info->type=UndefinedCache;
3994 (void) memset(image->channel_map,0,MaxPixelChannels*
3995 sizeof(*image->channel_map));
3996 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3997 "CacheResourcesExhausted","`%s'",image->filename);
3998 return(MagickFalse);
3999 }
4000 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode) &&
4001 (cache_info->mode != PersistMode))
4002 {
4003 (void) ClosePixelCacheOnDisk(cache_info);
4004 *cache_info->cache_filename='\0';
4005 }
4006 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4007 {
4008 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4009 RelinquishPixelCachePixels(&source_info);
4010 cache_info->type=UndefinedCache;
4011 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4012 image->filename);
4013 return(MagickFalse);
4014 }
4015 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
4016 cache_info->length);
4017 if (status == MagickFalse)
4018 {
4019 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4020 RelinquishPixelCachePixels(&source_info);
4021 cache_info->type=UndefinedCache;
4022 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4023 image->filename);
4024 return(MagickFalse);
4025 }
4026 cache_info->type=DiskCache;
4027 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4028 cache_info->metacontent_extent);
4029 if (length == (MagickSizeType) ((size_t) length))
4030 {
4031 status=AcquireMagickResource(MapResource,cache_info->length);
4032 if (status != MagickFalse)
4033 {
4034 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4035 cache_info->offset,(size_t) cache_info->length);
4036 if (cache_info->pixels == (Quantum *) NULL)
4037 {
4038 cache_info->mapped=source_info.mapped;
4039 cache_info->pixels=source_info.pixels;
4040 RelinquishMagickResource(MapResource,cache_info->length);
4041 }
4042 else
4043 {
4044 /*
4045 Create file-backed memory-mapped pixel cache.
4046 */
4047 (void) ClosePixelCacheOnDisk(cache_info);
4048 cache_info->type=MapCache;
4049 cache_info->mapped=MagickTrue;
4050 cache_info->metacontent=(void *) NULL;
4051 if (cache_info->metacontent_extent != 0)
4052 cache_info->metacontent=(void *) (cache_info->pixels+
4053 cache_info->number_channels*number_pixels);
4054 if ((source_info.storage_class != UndefinedClass) &&
4055 (mode != ReadMode))
4056 {
4057 status=ClonePixelCacheRepository(cache_info,&source_info,
4058 exception);
4059 RelinquishPixelCachePixels(&source_info);
4060 }
4061 if (cache_info->debug != MagickFalse)
4062 {
4063 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
4064 MagickPathExtent,format);
4065 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4066 cache_info->type);
4067 (void) FormatLocaleString(message,MagickPathExtent,
4068 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
4069 cache_info->filename,cache_info->cache_filename,
4070 cache_info->file,type,(double) cache_info->columns,
4071 (double) cache_info->rows,(double)
4072 cache_info->number_channels,format);
4073 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4074 message);
4075 }
4076 if (status == 0)
4077 {
4078 if ((source_info.storage_class != UndefinedClass) &&
4079 (mode != ReadMode))
4080 RelinquishPixelCachePixels(&source_info);
4081 cache_info->type=UndefinedCache;
4082 return(MagickFalse);
4083 }
4084 return(MagickTrue);
4085 }
4086 }
4087 }
4088 status=MagickTrue;
4089 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4090 {
4091 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
4092 RelinquishPixelCachePixels(&source_info);
4093 }
4094 if (cache_info->debug != MagickFalse)
4095 {
4096 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
4097 MagickPathExtent,format);
4098 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4099 cache_info->type);
4100 (void) FormatLocaleString(message,MagickPathExtent,
4101 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
4102 cache_info->cache_filename,cache_info->file,type,(double)
4103 cache_info->columns,(double) cache_info->rows,(double)
4104 cache_info->number_channels,format);
4105 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4106 }
4107 if (status == 0)
4108 {
4109 cache_info->type=UndefinedCache;
4110 return(MagickFalse);
4111 }
4112 return(MagickTrue);
4113}
4114
4115/*
4116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4117% %
4118% %
4119% %
4120+ P e r s i s t P i x e l C a c h e %
4121% %
4122% %
4123% %
4124%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4125%
4126% PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4127% persistent pixel cache is one that resides on disk and is not destroyed
4128% when the program exits.
4129%
4130% The format of the PersistPixelCache() method is:
4131%
4132% MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4133% const MagickBooleanType attach,MagickOffsetType *offset,
4134% ExceptionInfo *exception)
4135%
4136% A description of each parameter follows:
4137%
4138% o image: the image.
4139%
4140% o filename: the persistent pixel cache filename.
4141%
4142% o attach: A value other than zero initializes the persistent pixel cache.
4143%
4144% o initialize: A value other than zero initializes the persistent pixel
4145% cache.
4146%
4147% o offset: the offset in the persistent cache to store pixels.
4148%
4149% o exception: return any errors or warnings in this structure.
4150%
4151*/
4152MagickExport MagickBooleanType PersistPixelCache(Image *image,
4153 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4154 ExceptionInfo *exception)
4155{
4156 CacheInfo
4157 *magick_restrict cache_info,
4158 *magick_restrict clone_info;
4159
4160 MagickBooleanType
4161 status;
4162
4163 ssize_t
4164 page_size;
4165
4166 assert(image != (Image *) NULL);
4167 assert(image->signature == MagickCoreSignature);
4168 if (IsEventLogging() != MagickFalse)
4169 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4170 assert(image->cache != (void *) NULL);
4171 assert(filename != (const char *) NULL);
4172 assert(offset != (MagickOffsetType *) NULL);
4173 page_size=GetMagickPageSize();
4174 cache_info=(CacheInfo *) image->cache;
4175 assert(cache_info->signature == MagickCoreSignature);
4176#if defined(MAGICKCORE_OPENCL_SUPPORT)
4177 CopyOpenCLBuffer(cache_info);
4178#endif
4179 if (attach != MagickFalse)
4180 {
4181 /*
4182 Attach existing persistent pixel cache.
4183 */
4184 if (cache_info->debug != MagickFalse)
4185 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4186 "attach persistent cache");
4187 (void) CopyMagickString(cache_info->cache_filename,filename,
4188 MagickPathExtent);
4189 cache_info->type=MapCache;
4190 cache_info->offset=(*offset);
4191 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4192 return(MagickFalse);
4193 *offset=(*offset+(MagickOffsetType) cache_info->length+page_size-
4194 ((MagickOffsetType) cache_info->length % page_size));
4195 return(MagickTrue);
4196 }
4197 /*
4198 Clone persistent pixel cache.
4199 */
4200 status=AcquireMagickResource(DiskResource,cache_info->length);
4201 if (status == MagickFalse)
4202 {
4203 cache_info->type=UndefinedCache;
4204 (void) memset(image->channel_map,0,MaxPixelChannels*
4205 sizeof(*image->channel_map));
4206 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4207 "CacheResourcesExhausted","`%s'",image->filename);
4208 return(MagickFalse);
4209 }
4210 clone_info=(CacheInfo *) ClonePixelCache(cache_info);
4211 clone_info->type=DiskCache;
4212 (void) CopyMagickString(clone_info->cache_filename,filename,MagickPathExtent);
4213 clone_info->file=(-1);
4214 clone_info->storage_class=cache_info->storage_class;
4215 clone_info->colorspace=cache_info->colorspace;
4216 clone_info->alpha_trait=cache_info->alpha_trait;
4217 clone_info->channels=cache_info->channels;
4218 clone_info->columns=cache_info->columns;
4219 clone_info->rows=cache_info->rows;
4220 clone_info->number_channels=cache_info->number_channels;
4221 clone_info->metacontent_extent=cache_info->metacontent_extent;
4222 clone_info->mode=PersistMode;
4223 clone_info->length=cache_info->length;
4224 (void) memcpy(clone_info->channel_map,cache_info->channel_map,
4225 MaxPixelChannels*sizeof(*cache_info->channel_map));
4226 clone_info->offset=(*offset);
4227 status=OpenPixelCacheOnDisk(clone_info,WriteMode);
4228 if (status != MagickFalse)
4229 status=ClonePixelCacheRepository(clone_info,cache_info,exception);
4230 *offset=(*offset+(MagickOffsetType) cache_info->length+page_size-
4231 ((MagickOffsetType) cache_info->length % page_size));
4232 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4233 return(status);
4234}
4235
4236/*
4237%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4238% %
4239% %
4240% %
4241+ 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 %
4242% %
4243% %
4244% %
4245%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4246%
4247% QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4248% defined by the region rectangle and returns a pointer to the region. This
4249% region is subsequently transferred from the pixel cache with
4250% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4251% pixels are transferred, otherwise a NULL is returned.
4252%
4253% The format of the QueueAuthenticPixelCacheNexus() method is:
4254%
4255% Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4256% const ssize_t y,const size_t columns,const size_t rows,
4257% const MagickBooleanType clone,NexusInfo *nexus_info,
4258% ExceptionInfo *exception)
4259%
4260% A description of each parameter follows:
4261%
4262% o image: the image.
4263%
4264% o x,y,columns,rows: These values define the perimeter of a region of
4265% pixels.
4266%
4267% o nexus_info: the cache nexus to set.
4268%
4269% o clone: clone the pixel cache.
4270%
4271% o exception: return any errors or warnings in this structure.
4272%
4273*/
4274MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4275 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4276 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4277{
4278 CacheInfo
4279 *magick_restrict cache_info;
4280
4281 MagickOffsetType
4282 offset;
4283
4284 MagickSizeType
4285 number_pixels;
4286
4287 Quantum
4288 *magick_restrict pixels;
4289
4290 /*
4291 Validate pixel cache geometry.
4292 */
4293 assert(image != (const Image *) NULL);
4294 assert(image->signature == MagickCoreSignature);
4295 assert(image->cache != (Cache) NULL);
4296 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4297 if (cache_info == (Cache) NULL)
4298 return((Quantum *) NULL);
4299 assert(cache_info->signature == MagickCoreSignature);
4300 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
4301 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4302 (y >= (ssize_t) cache_info->rows))
4303 {
4304 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4305 "PixelsAreNotAuthentic","`%s'",image->filename);
4306 return((Quantum *) NULL);
4307 }
4308 if (IsValidPixelOffset(y,cache_info->columns) == MagickFalse)
4309 return((Quantum *) NULL);
4310 offset=y*(MagickOffsetType) cache_info->columns+x;
4311 if (offset < 0)
4312 return((Quantum *) NULL);
4313 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4314 offset+=((MagickOffsetType) rows-1)*(MagickOffsetType) cache_info->columns+
4315 (MagickOffsetType) columns-1;
4316 if ((MagickSizeType) offset >= number_pixels)
4317 return((Quantum *) NULL);
4318 /*
4319 Return pixel cache.
4320 */
4321 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,x,y,columns,rows,
4322 ((image->channels & WriteMaskChannel) != 0) ||
4323 ((image->channels & CompositeMaskChannel) != 0) ? MagickTrue : MagickFalse,
4324 nexus_info,exception);
4325 return(pixels);
4326}
4327
4328/*
4329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4330% %
4331% %
4332% %
4333+ 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 %
4334% %
4335% %
4336% %
4337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4338%
4339% QueueAuthenticPixelsCache() allocates an region to store image pixels as
4340% defined by the region rectangle and returns a pointer to the region. This
4341% region is subsequently transferred from the pixel cache with
4342% SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4343% pixels are transferred, otherwise a NULL is returned.
4344%
4345% The format of the QueueAuthenticPixelsCache() method is:
4346%
4347% Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4348% const ssize_t y,const size_t columns,const size_t rows,
4349% ExceptionInfo *exception)
4350%
4351% A description of each parameter follows:
4352%
4353% o image: the image.
4354%
4355% o x,y,columns,rows: These values define the perimeter of a region of
4356% pixels.
4357%
4358% o exception: return any errors or warnings in this structure.
4359%
4360*/
4361static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4362 const ssize_t y,const size_t columns,const size_t rows,
4363 ExceptionInfo *exception)
4364{
4365 CacheInfo
4366 *magick_restrict cache_info;
4367
4368 const int
4369 id = GetOpenMPThreadId();
4370
4371 Quantum
4372 *magick_restrict pixels;
4373
4374 assert(image != (const Image *) NULL);
4375 assert(image->signature == MagickCoreSignature);
4376 assert(image->cache != (Cache) NULL);
4377 cache_info=(CacheInfo *) image->cache;
4378 assert(cache_info->signature == MagickCoreSignature);
4379 assert(id < (int) cache_info->number_threads);
4380 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4381 cache_info->nexus_info[id],exception);
4382 return(pixels);
4383}
4384
4385/*
4386%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4387% %
4388% %
4389% %
4390% Q u e u e A u t h e n t i c P i x e l s %
4391% %
4392% %
4393% %
4394%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4395%
4396% QueueAuthenticPixels() queues a mutable pixel region. If the region is
4397% successfully initialized a pointer to a Quantum array representing the
4398% region is returned, otherwise NULL is returned. The returned pointer may
4399% point to a temporary working buffer for the pixels or it may point to the
4400% final location of the pixels in memory.
4401%
4402% Write-only access means that any existing pixel values corresponding to
4403% the region are ignored. This is useful if the initial image is being
4404% created from scratch, or if the existing pixel values are to be
4405% completely replaced without need to refer to their preexisting values.
4406% The application is free to read and write the pixel buffer returned by
4407% QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4408% initialize the pixel array values. Initializing pixel array values is the
4409% application's responsibility.
4410%
4411% Performance is maximized if the selected region is part of one row, or
4412% one or more full rows, since then there is opportunity to access the
4413% pixels in-place (without a copy) if the image is in memory, or in a
4414% memory-mapped file. The returned pointer must *never* be deallocated
4415% by the user.
4416%
4417% Pixels accessed via the returned pointer represent a simple array of type
4418% Quantum. If the image type is CMYK or the storage class is PseudoClass,
4419% call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4420% obtain the meta-content (of type void) corresponding to the region.
4421% Once the Quantum (and/or Quantum) array has been updated, the
4422% changes must be saved back to the underlying image using
4423% SyncAuthenticPixels() or they may be lost.
4424%
4425% The format of the QueueAuthenticPixels() method is:
4426%
4427% Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4428% const ssize_t y,const size_t columns,const size_t rows,
4429% ExceptionInfo *exception)
4430%
4431% A description of each parameter follows:
4432%
4433% o image: the image.
4434%
4435% o x,y,columns,rows: These values define the perimeter of a region of
4436% pixels.
4437%
4438% o exception: return any errors or warnings in this structure.
4439%
4440*/
4441MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4442 const ssize_t y,const size_t columns,const size_t rows,
4443 ExceptionInfo *exception)
4444{
4445 CacheInfo
4446 *magick_restrict cache_info;
4447
4448 const int
4449 id = GetOpenMPThreadId();
4450
4451 Quantum
4452 *magick_restrict pixels;
4453
4454 assert(image != (Image *) NULL);
4455 assert(image->signature == MagickCoreSignature);
4456 assert(image->cache != (Cache) NULL);
4457 cache_info=(CacheInfo *) image->cache;
4458 assert(cache_info->signature == MagickCoreSignature);
4459 if (cache_info->methods.queue_authentic_pixels_handler !=
4460 (QueueAuthenticPixelsHandler) NULL)
4461 {
4462 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4463 columns,rows,exception);
4464 return(pixels);
4465 }
4466 assert(id < (int) cache_info->number_threads);
4467 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4468 cache_info->nexus_info[id],exception);
4469 return(pixels);
4470}
4471
4472/*
4473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4474% %
4475% %
4476% %
4477+ 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 %
4478% %
4479% %
4480% %
4481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4482%
4483% ReadPixelCacheMetacontent() reads metacontent from the specified region of
4484% the pixel cache.
4485%
4486% The format of the ReadPixelCacheMetacontent() method is:
4487%
4488% MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4489% NexusInfo *nexus_info,ExceptionInfo *exception)
4490%
4491% A description of each parameter follows:
4492%
4493% o cache_info: the pixel cache.
4494%
4495% o nexus_info: the cache nexus to read the metacontent.
4496%
4497% o exception: return any errors or warnings in this structure.
4498%
4499*/
4500
4501static inline MagickOffsetType ReadPixelCacheRegion(
4502 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4503 const MagickSizeType length,unsigned char *magick_restrict buffer)
4504{
4505 MagickOffsetType
4506 i;
4507
4508 ssize_t
4509 count = 0;
4510
4511#if !defined(MAGICKCORE_HAVE_PREAD)
4512 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4513 return((MagickOffsetType) -1);
4514#endif
4515 for (i=0; i < (MagickOffsetType) length; i+=count)
4516 {
4517#if !defined(MAGICKCORE_HAVE_PREAD)
4518 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-
4519 (MagickSizeType) i,(size_t) MagickMaxBufferExtent));
4520#else
4521 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-
4522 (MagickSizeType) i,(size_t) MagickMaxBufferExtent),offset+i);
4523#endif
4524 if (count <= 0)
4525 {
4526 count=0;
4527 if (errno != EINTR)
4528 break;
4529 }
4530 }
4531 return(i);
4532}
4533
4534static MagickBooleanType ReadPixelCacheMetacontent(
4535 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4536 ExceptionInfo *exception)
4537{
4538 MagickOffsetType
4539 count,
4540 offset;
4541
4542 MagickSizeType
4543 extent,
4544 length;
4545
4546 ssize_t
4547 y;
4548
4549 unsigned char
4550 *magick_restrict q;
4551
4552 size_t
4553 rows;
4554
4555 if (cache_info->metacontent_extent == 0)
4556 return(MagickFalse);
4557 if (nexus_info->authentic_pixel_cache != MagickFalse)
4558 return(MagickTrue);
4559 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
4560 return(MagickFalse);
4561 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
4562 nexus_info->region.x;
4563 length=(MagickSizeType) nexus_info->region.width*
4564 cache_info->metacontent_extent;
4565 extent=length*nexus_info->region.height;
4566 rows=nexus_info->region.height;
4567 y=0;
4568 q=(unsigned char *) nexus_info->metacontent;
4569 switch (cache_info->type)
4570 {
4571 case MemoryCache:
4572 case MapCache:
4573 {
4574 unsigned char
4575 *magick_restrict p;
4576
4577 /*
4578 Read meta-content from memory.
4579 */
4580 if ((cache_info->columns == nexus_info->region.width) &&
4581 (extent == (MagickSizeType) ((size_t) extent)))
4582 {
4583 length=extent;
4584 rows=1UL;
4585 }
4586 p=(unsigned char *) cache_info->metacontent+offset*(MagickOffsetType)
4587 cache_info->metacontent_extent;
4588 for (y=0; y < (ssize_t) rows; y++)
4589 {
4590 (void) memcpy(q,p,(size_t) length);
4591 p+=(ptrdiff_t) cache_info->metacontent_extent*cache_info->columns;
4592 q+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
4593 }
4594 break;
4595 }
4596 case DiskCache:
4597 {
4598 /*
4599 Read meta content from disk.
4600 */
4601 LockSemaphoreInfo(cache_info->file_semaphore);
4602 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4603 {
4604 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4605 cache_info->cache_filename);
4606 UnlockSemaphoreInfo(cache_info->file_semaphore);
4607 return(MagickFalse);
4608 }
4609 if ((cache_info->columns == nexus_info->region.width) &&
4610 (extent <= MagickMaxBufferExtent))
4611 {
4612 length=extent;
4613 rows=1UL;
4614 }
4615 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4616 for (y=0; y < (ssize_t) rows; y++)
4617 {
4618 count=ReadPixelCacheRegion(cache_info,cache_info->offset+
4619 (MagickOffsetType) extent*(MagickOffsetType)
4620 cache_info->number_channels*(MagickOffsetType) sizeof(Quantum)+offset*
4621 (MagickOffsetType) cache_info->metacontent_extent,length,
4622 (unsigned char *) q);
4623 if (count != (MagickOffsetType) length)
4624 break;
4625 offset+=(MagickOffsetType) cache_info->columns;
4626 q+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
4627 }
4628 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4629 (void) ClosePixelCacheOnDisk(cache_info);
4630 UnlockSemaphoreInfo(cache_info->file_semaphore);
4631 break;
4632 }
4633 case DistributedCache:
4634 {
4635 RectangleInfo
4636 region;
4637
4638 /*
4639 Read metacontent from distributed cache.
4640 */
4641 LockSemaphoreInfo(cache_info->file_semaphore);
4642 region=nexus_info->region;
4643 if ((cache_info->columns != nexus_info->region.width) ||
4644 (extent > MagickMaxBufferExtent))
4645 region.height=1UL;
4646 else
4647 {
4648 length=extent;
4649 rows=1UL;
4650 }
4651 for (y=0; y < (ssize_t) rows; y++)
4652 {
4653 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4654 cache_info->server_info,&region,length,(unsigned char *) q);
4655 if (count != (MagickOffsetType) length)
4656 break;
4657 q+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
4658 region.y++;
4659 }
4660 UnlockSemaphoreInfo(cache_info->file_semaphore);
4661 break;
4662 }
4663 default:
4664 break;
4665 }
4666 if (y < (ssize_t) rows)
4667 {
4668 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4669 cache_info->cache_filename);
4670 return(MagickFalse);
4671 }
4672 if ((cache_info->debug != MagickFalse) &&
4673 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4674 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4675 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4676 nexus_info->region.width,(double) nexus_info->region.height,(double)
4677 nexus_info->region.x,(double) nexus_info->region.y);
4678 return(MagickTrue);
4679}
4680
4681/*
4682%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4683% %
4684% %
4685% %
4686+ R e a d P i x e l C a c h e P i x e l s %
4687% %
4688% %
4689% %
4690%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4691%
4692% ReadPixelCachePixels() reads pixels from the specified region of the pixel
4693% cache.
4694%
4695% The format of the ReadPixelCachePixels() method is:
4696%
4697% MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4698% NexusInfo *nexus_info,ExceptionInfo *exception)
4699%
4700% A description of each parameter follows:
4701%
4702% o cache_info: the pixel cache.
4703%
4704% o nexus_info: the cache nexus to read the pixels.
4705%
4706% o exception: return any errors or warnings in this structure.
4707%
4708*/
4709static MagickBooleanType ReadPixelCachePixels(
4710 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4711 ExceptionInfo *exception)
4712{
4713 MagickOffsetType
4714 count,
4715 offset;
4716
4717 MagickSizeType
4718 extent,
4719 length;
4720
4721 Quantum
4722 *magick_restrict q;
4723
4724 size_t
4725 number_channels,
4726 rows;
4727
4728 ssize_t
4729 y;
4730
4731 if (nexus_info->authentic_pixel_cache != MagickFalse)
4732 return(MagickTrue);
4733 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
4734 return(MagickFalse);
4735 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns;
4736 if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4737 return(MagickFalse);
4738 offset+=nexus_info->region.x;
4739 number_channels=cache_info->number_channels;
4740 length=(MagickSizeType) number_channels*nexus_info->region.width*
4741 sizeof(Quantum);
4742 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4743 return(MagickFalse);
4744 rows=nexus_info->region.height;
4745 extent=length*rows;
4746 if ((extent == 0) || ((extent/length) != rows))
4747 return(MagickFalse);
4748 y=0;
4749 q=nexus_info->pixels;
4750 switch (cache_info->type)
4751 {
4752 case MemoryCache:
4753 case MapCache:
4754 {
4755 Quantum
4756 *magick_restrict p;
4757
4758 /*
4759 Read pixels from memory.
4760 */
4761 if ((cache_info->columns == nexus_info->region.width) &&
4762 (extent == (MagickSizeType) ((size_t) extent)))
4763 {
4764 length=extent;
4765 rows=1UL;
4766 }
4767 p=cache_info->pixels+(MagickOffsetType) cache_info->number_channels*
4768 offset;
4769 for (y=0; y < (ssize_t) rows; y++)
4770 {
4771 (void) memcpy(q,p,(size_t) length);
4772 p+=(ptrdiff_t) cache_info->number_channels*cache_info->columns;
4773 q+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
4774 }
4775 break;
4776 }
4777 case DiskCache:
4778 {
4779 /*
4780 Read pixels from disk.
4781 */
4782 LockSemaphoreInfo(cache_info->file_semaphore);
4783 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4784 {
4785 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4786 cache_info->cache_filename);
4787 UnlockSemaphoreInfo(cache_info->file_semaphore);
4788 return(MagickFalse);
4789 }
4790 if ((cache_info->columns == nexus_info->region.width) &&
4791 (extent <= MagickMaxBufferExtent))
4792 {
4793 length=extent;
4794 rows=1UL;
4795 }
4796 for (y=0; y < (ssize_t) rows; y++)
4797 {
4798 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4799 (MagickOffsetType) cache_info->number_channels*(MagickOffsetType)
4800 sizeof(*q),length,(unsigned char *) q);
4801 if (count != (MagickOffsetType) length)
4802 break;
4803 offset+=(MagickOffsetType) cache_info->columns;
4804 q+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
4805 }
4806 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4807 (void) ClosePixelCacheOnDisk(cache_info);
4808 UnlockSemaphoreInfo(cache_info->file_semaphore);
4809 break;
4810 }
4811 case DistributedCache:
4812 {
4813 RectangleInfo
4814 region;
4815
4816 /*
4817 Read pixels from distributed cache.
4818 */
4819 LockSemaphoreInfo(cache_info->file_semaphore);
4820 region=nexus_info->region;
4821 if ((cache_info->columns != nexus_info->region.width) ||
4822 (extent > MagickMaxBufferExtent))
4823 region.height=1UL;
4824 else
4825 {
4826 length=extent;
4827 rows=1UL;
4828 }
4829 for (y=0; y < (ssize_t) rows; y++)
4830 {
4831 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4832 cache_info->server_info,&region,length,(unsigned char *) q);
4833 if (count != (MagickOffsetType) length)
4834 break;
4835 q+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
4836 region.y++;
4837 }
4838 UnlockSemaphoreInfo(cache_info->file_semaphore);
4839 break;
4840 }
4841 default:
4842 break;
4843 }
4844 if (y < (ssize_t) rows)
4845 {
4846 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4847 cache_info->cache_filename);
4848 return(MagickFalse);
4849 }
4850 if ((cache_info->debug != MagickFalse) &&
4851 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4852 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4853 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4854 nexus_info->region.width,(double) nexus_info->region.height,(double)
4855 nexus_info->region.x,(double) nexus_info->region.y);
4856 return(MagickTrue);
4857}
4858
4859/*
4860%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4861% %
4862% %
4863% %
4864+ R e f e r e n c e P i x e l C a c h e %
4865% %
4866% %
4867% %
4868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4869%
4870% ReferencePixelCache() increments the reference count associated with the
4871% pixel cache returning a pointer to the cache.
4872%
4873% The format of the ReferencePixelCache method is:
4874%
4875% Cache ReferencePixelCache(Cache cache_info)
4876%
4877% A description of each parameter follows:
4878%
4879% o cache_info: the pixel cache.
4880%
4881*/
4882MagickPrivate Cache ReferencePixelCache(Cache cache)
4883{
4884 CacheInfo
4885 *magick_restrict cache_info;
4886
4887 assert(cache != (Cache *) NULL);
4888 cache_info=(CacheInfo *) cache;
4889 assert(cache_info->signature == MagickCoreSignature);
4890 LockSemaphoreInfo(cache_info->semaphore);
4891 cache_info->reference_count++;
4892 UnlockSemaphoreInfo(cache_info->semaphore);
4893 return(cache_info);
4894}
4895
4896/*
4897%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4898% %
4899% %
4900% %
4901+ R e s e t P i x e l C a c h e C h a n n e l s %
4902% %
4903% %
4904% %
4905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4906%
4907% ResetPixelCacheChannels() resets the pixel cache channels.
4908%
4909% The format of the ResetPixelCacheChannels method is:
4910%
4911% void ResetPixelCacheChannels(Image *)
4912%
4913% A description of each parameter follows:
4914%
4915% o image: the image.
4916%
4917*/
4918MagickPrivate void ResetPixelCacheChannels(Image *image)
4919{
4920 CacheInfo
4921 *magick_restrict cache_info;
4922
4923 assert(image != (const Image *) NULL);
4924 assert(image->signature == MagickCoreSignature);
4925 assert(image->cache != (Cache) NULL);
4926 cache_info=(CacheInfo *) image->cache;
4927 assert(cache_info->signature == MagickCoreSignature);
4928 cache_info->number_channels=GetPixelChannels(image);
4929}
4930
4931/*
4932%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4933% %
4934% %
4935% %
4936+ 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 %
4937% %
4938% %
4939% %
4940%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4941%
4942% ResetCacheAnonymousMemory() resets the anonymous_memory value.
4943%
4944% The format of the ResetCacheAnonymousMemory method is:
4945%
4946% void ResetCacheAnonymousMemory(void)
4947%
4948*/
4949MagickPrivate void ResetCacheAnonymousMemory(void)
4950{
4951 cache_anonymous_memory=0;
4952}
4953
4954/*
4955%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4956% %
4957% %
4958% %
4959% R e s h a p e P i x e l C a c h e %
4960% %
4961% %
4962% %
4963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4964%
4965% ReshapePixelCache() reshapes an existing pixel cache.
4966%
4967% The format of the ReshapePixelCache() method is:
4968%
4969% MagickBooleanType ReshapePixelCache(Image *image,const size_t columns,
4970% const size_t rows,ExceptionInfo *exception)
4971%
4972% A description of each parameter follows:
4973%
4974% o image: the image.
4975%
4976% o columns: the number of columns in the reshaped pixel cache.
4977%
4978% o rows: number of rows in the reshaped pixel cache.
4979%
4980% o exception: return any errors or warnings in this structure.
4981%
4982*/
4983MagickExport MagickBooleanType ReshapePixelCache(Image *image,
4984 const size_t columns,const size_t rows,ExceptionInfo *exception)
4985{
4986 CacheInfo
4987 *cache_info;
4988
4989 MagickSizeType
4990 extent;
4991
4992 assert(image != (Image *) NULL);
4993 assert(image->signature == MagickCoreSignature);
4994 if (IsEventLogging() != MagickFalse)
4995 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4996 assert(image->cache != (void *) NULL);
4997 extent=(MagickSizeType) columns*rows;
4998 if (extent > ((MagickSizeType) image->columns*image->rows))
4999 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
5000 image->filename);
5001 image->columns=columns;
5002 image->rows=rows;
5003 cache_info=(CacheInfo *) image->cache;
5004 cache_info->columns=columns;
5005 cache_info->rows=rows;
5006 return(SyncImagePixelCache(image,exception));
5007}
5008
5009/*
5010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5011% %
5012% %
5013% %
5014+ S e t P i x e l C a c h e M e t h o d s %
5015% %
5016% %
5017% %
5018%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5019%
5020% SetPixelCacheMethods() sets the image pixel methods to the specified ones.
5021%
5022% The format of the SetPixelCacheMethods() method is:
5023%
5024% SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
5025%
5026% A description of each parameter follows:
5027%
5028% o cache: the pixel cache.
5029%
5030% o cache_methods: Specifies a pointer to a CacheMethods structure.
5031%
5032*/
5033MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
5034{
5035 CacheInfo
5036 *magick_restrict cache_info;
5037
5038 GetOneAuthenticPixelFromHandler
5039 get_one_authentic_pixel_from_handler;
5040
5041 GetOneVirtualPixelFromHandler
5042 get_one_virtual_pixel_from_handler;
5043
5044 /*
5045 Set cache pixel methods.
5046 */
5047 assert(cache != (Cache) NULL);
5048 assert(cache_methods != (CacheMethods *) NULL);
5049 cache_info=(CacheInfo *) cache;
5050 assert(cache_info->signature == MagickCoreSignature);
5051 if (IsEventLogging() != MagickFalse)
5052 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5053 cache_info->filename);
5054 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
5055 cache_info->methods.get_virtual_pixel_handler=
5056 cache_methods->get_virtual_pixel_handler;
5057 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
5058 cache_info->methods.destroy_pixel_handler=
5059 cache_methods->destroy_pixel_handler;
5060 if (cache_methods->get_virtual_metacontent_from_handler !=
5061 (GetVirtualMetacontentFromHandler) NULL)
5062 cache_info->methods.get_virtual_metacontent_from_handler=
5063 cache_methods->get_virtual_metacontent_from_handler;
5064 if (cache_methods->get_authentic_pixels_handler !=
5065 (GetAuthenticPixelsHandler) NULL)
5066 cache_info->methods.get_authentic_pixels_handler=
5067 cache_methods->get_authentic_pixels_handler;
5068 if (cache_methods->queue_authentic_pixels_handler !=
5069 (QueueAuthenticPixelsHandler) NULL)
5070 cache_info->methods.queue_authentic_pixels_handler=
5071 cache_methods->queue_authentic_pixels_handler;
5072 if (cache_methods->sync_authentic_pixels_handler !=
5073 (SyncAuthenticPixelsHandler) NULL)
5074 cache_info->methods.sync_authentic_pixels_handler=
5075 cache_methods->sync_authentic_pixels_handler;
5076 if (cache_methods->get_authentic_pixels_from_handler !=
5077 (GetAuthenticPixelsFromHandler) NULL)
5078 cache_info->methods.get_authentic_pixels_from_handler=
5079 cache_methods->get_authentic_pixels_from_handler;
5080 if (cache_methods->get_authentic_metacontent_from_handler !=
5081 (GetAuthenticMetacontentFromHandler) NULL)
5082 cache_info->methods.get_authentic_metacontent_from_handler=
5083 cache_methods->get_authentic_metacontent_from_handler;
5084 get_one_virtual_pixel_from_handler=
5085 cache_info->methods.get_one_virtual_pixel_from_handler;
5086 if (get_one_virtual_pixel_from_handler !=
5087 (GetOneVirtualPixelFromHandler) NULL)
5088 cache_info->methods.get_one_virtual_pixel_from_handler=
5089 cache_methods->get_one_virtual_pixel_from_handler;
5090 get_one_authentic_pixel_from_handler=
5091 cache_methods->get_one_authentic_pixel_from_handler;
5092 if (get_one_authentic_pixel_from_handler !=
5093 (GetOneAuthenticPixelFromHandler) NULL)
5094 cache_info->methods.get_one_authentic_pixel_from_handler=
5095 cache_methods->get_one_authentic_pixel_from_handler;
5096}
5097
5098/*
5099%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5100% %
5101% %
5102% %
5103+ S e t P i x e l C a c h e N e x u s P i x e l s %
5104% %
5105% %
5106% %
5107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5108%
5109% SetPixelCacheNexusPixels() defines the region of the cache for the
5110% specified cache nexus.
5111%
5112% The format of the SetPixelCacheNexusPixels() method is:
5113%
5114% Quantum SetPixelCacheNexusPixels(
5115% const CacheInfo *magick_restrict cache_info,const MapMode mode,
5116% const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5117% const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5118% ExceptionInfo *exception)
5119%
5120% A description of each parameter follows:
5121%
5122% o cache_info: the pixel cache.
5123%
5124% o mode: ReadMode, WriteMode, or IOMode.
5125%
5126% o x,y,width,height: define the region of this particular cache nexus.
5127%
5128% o buffered: if true, nexus pixels are buffered.
5129%
5130% o nexus_info: the cache nexus to set.
5131%
5132% o exception: return any errors or warnings in this structure.
5133%
5134*/
5135
5136static inline MagickBooleanType AcquireCacheNexusPixels(
5137 const CacheInfo *magick_restrict cache_info,const MagickSizeType length,
5138 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5139{
5140 if (length != (MagickSizeType) ((size_t) length))
5141 {
5142 (void) ThrowMagickException(exception,GetMagickModule(),
5143 ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
5144 cache_info->filename);
5145 return(MagickFalse);
5146 }
5147 nexus_info->length=0;
5148 nexus_info->mapped=MagickFalse;
5149 if (cache_anonymous_memory <= 0)
5150 {
5151 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
5152 (size_t) length));
5153 if (nexus_info->cache != (Quantum *) NULL)
5154 (void) memset(nexus_info->cache,0,(size_t) length);
5155 }
5156 else
5157 {
5158 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t) length);
5159 if (nexus_info->cache != (Quantum *) NULL)
5160 nexus_info->mapped=MagickTrue;
5161 }
5162 if (nexus_info->cache == (Quantum *) NULL)
5163 {
5164 (void) ThrowMagickException(exception,GetMagickModule(),
5165 ResourceLimitError,"PixelCacheAllocationFailed","`%s'",
5166 cache_info->filename);
5167 return(MagickFalse);
5168 }
5169 nexus_info->length=length;
5170 return(MagickTrue);
5171}
5172
5173static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
5174 const MapMode mode)
5175{
5176 if (nexus_info->length < CACHE_LINE_SIZE)
5177 return;
5178 if (mode == ReadMode)
5179 {
5180 MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,
5181 0,1);
5182 return;
5183 }
5184 MagickCachePrefetch((unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,1,1);
5185}
5186
5187static Quantum *SetPixelCacheNexusPixels(
5188 const CacheInfo *magick_restrict cache_info,const MapMode mode,
5189 const ssize_t x,const ssize_t y,const size_t width,const size_t height,
5190 const MagickBooleanType buffered,NexusInfo *magick_restrict nexus_info,
5191 ExceptionInfo *exception)
5192{
5193 MagickBooleanType
5194 status;
5195
5196 MagickSizeType
5197 length,
5198 number_pixels;
5199
5200 assert(cache_info != (const CacheInfo *) NULL);
5201 assert(cache_info->signature == MagickCoreSignature);
5202 if (cache_info->type == UndefinedCache)
5203 return((Quantum *) NULL);
5204 assert(nexus_info->signature == MagickCoreSignature);
5205 (void) memset(&nexus_info->region,0,sizeof(nexus_info->region));
5206 if ((width == 0) || (height == 0))
5207 {
5208 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
5209 "NoPixelsDefinedInCache","`%s'",cache_info->filename);
5210 return((Quantum *) NULL);
5211 }
5212 if (((MagickSizeType) width > cache_info->width_limit) ||
5213 ((MagickSizeType) height > cache_info->height_limit))
5214 {
5215 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
5216 "WidthOrHeightExceedsLimit","`%s'",cache_info->filename);
5217 return((Quantum *) NULL);
5218 }
5219 if ((IsValidPixelOffset(x,width) == MagickFalse) ||
5220 (IsValidPixelOffset(y,height) == MagickFalse))
5221 {
5222 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
5223 "InvalidPixel","`%s'",cache_info->filename);
5224 return((Quantum *) NULL);
5225 }
5226 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
5227 (buffered == MagickFalse))
5228 {
5229 if (((x >= 0) && (y >= 0) &&
5230 (((ssize_t) height+y-1) < (ssize_t) cache_info->rows)) &&
5231 (((x == 0) && (width == cache_info->columns)) || ((height == 1) &&
5232 (((ssize_t) width+x-1) < (ssize_t) cache_info->columns))))
5233 {
5234 MagickOffsetType
5235 offset;
5236
5237 /*
5238 Pixels are accessed directly from memory.
5239 */
5240 if (IsValidPixelOffset(y,cache_info->columns) == MagickFalse)
5241 return((Quantum *) NULL);
5242 offset=y*(MagickOffsetType) cache_info->columns+x;
5243 nexus_info->pixels=cache_info->pixels+(MagickOffsetType)
5244 cache_info->number_channels*offset;
5245 nexus_info->metacontent=(void *) NULL;
5246 if (cache_info->metacontent_extent != 0)
5247 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5248 offset*(MagickOffsetType) cache_info->metacontent_extent;
5249 nexus_info->region.width=width;
5250 nexus_info->region.height=height;
5251 nexus_info->region.x=x;
5252 nexus_info->region.y=y;
5253 nexus_info->authentic_pixel_cache=MagickTrue;
5254 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5255 return(nexus_info->pixels);
5256 }
5257 }
5258 /*
5259 Pixels are stored in a staging region until they are synced to the cache.
5260 */
5261 number_pixels=(MagickSizeType) width*height;
5262 length=MagickMax(number_pixels,MagickMax(cache_info->columns,
5263 cache_info->rows))*cache_info->number_channels*sizeof(*nexus_info->pixels);
5264 if (cache_info->metacontent_extent != 0)
5265 length+=number_pixels*cache_info->metacontent_extent;
5266 status=MagickTrue;
5267 if (nexus_info->cache == (Quantum *) NULL)
5268 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5269 else
5270 if (nexus_info->length < length)
5271 {
5272 RelinquishCacheNexusPixels(nexus_info);
5273 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5274 }
5275 if (status == MagickFalse)
5276 return((Quantum *) NULL);
5277 nexus_info->pixels=nexus_info->cache;
5278 nexus_info->metacontent=(void *) NULL;
5279 if (cache_info->metacontent_extent != 0)
5280 nexus_info->metacontent=(void *) (nexus_info->pixels+
5281 cache_info->number_channels*number_pixels);
5282 nexus_info->region.width=width;
5283 nexus_info->region.height=height;
5284 nexus_info->region.x=x;
5285 nexus_info->region.y=y;
5286 nexus_info->authentic_pixel_cache=cache_info->type == PingCache ?
5287 MagickTrue : MagickFalse;
5288 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5289 return(nexus_info->pixels);
5290}
5291
5292/*
5293%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5294% %
5295% %
5296% %
5297% 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 %
5298% %
5299% %
5300% %
5301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5302%
5303% SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5304% pixel cache and returns the previous setting. A virtual pixel is any pixel
5305% access that is outside the boundaries of the image cache.
5306%
5307% The format of the SetPixelCacheVirtualMethod() method is:
5308%
5309% VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5310% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5311%
5312% A description of each parameter follows:
5313%
5314% o image: the image.
5315%
5316% o virtual_pixel_method: choose the type of virtual pixel.
5317%
5318% o exception: return any errors or warnings in this structure.
5319%
5320*/
5321
5322static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
5323 ExceptionInfo *exception)
5324{
5325 CacheView
5326 *magick_restrict image_view;
5327
5328 MagickBooleanType
5329 status;
5330
5331 ssize_t
5332 y;
5333
5334 assert(image != (Image *) NULL);
5335 assert(image->signature == MagickCoreSignature);
5336 if (IsEventLogging() != MagickFalse)
5337 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5338 assert(image->cache != (Cache) NULL);
5339 image->alpha_trait=BlendPixelTrait;
5340 status=MagickTrue;
5341 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
5342#if defined(MAGICKCORE_OPENMP_SUPPORT)
5343 #pragma omp parallel for schedule(static) shared(status) \
5344 magick_number_threads(image,image,image->rows,2)
5345#endif
5346 for (y=0; y < (ssize_t) image->rows; y++)
5347 {
5348 Quantum
5349 *magick_restrict q;
5350
5351 ssize_t
5352 x;
5353
5354 if (status == MagickFalse)
5355 continue;
5356 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5357 if (q == (Quantum *) NULL)
5358 {
5359 status=MagickFalse;
5360 continue;
5361 }
5362 for (x=0; x < (ssize_t) image->columns; x++)
5363 {
5364 SetPixelAlpha(image,alpha,q);
5365 q+=(ptrdiff_t) GetPixelChannels(image);
5366 }
5367 status=SyncCacheViewAuthenticPixels(image_view,exception);
5368 }
5369 image_view=DestroyCacheView(image_view);
5370 return(status);
5371}
5372
5373MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5374 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5375{
5376 CacheInfo
5377 *magick_restrict cache_info;
5378
5379 VirtualPixelMethod
5380 method;
5381
5382 assert(image != (Image *) NULL);
5383 assert(image->signature == MagickCoreSignature);
5384 if (IsEventLogging() != MagickFalse)
5385 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5386 assert(image->cache != (Cache) NULL);
5387 cache_info=(CacheInfo *) image->cache;
5388 assert(cache_info->signature == MagickCoreSignature);
5389 method=cache_info->virtual_pixel_method;
5390 cache_info->virtual_pixel_method=virtual_pixel_method;
5391 if ((image->columns != 0) && (image->rows != 0))
5392 switch (virtual_pixel_method)
5393 {
5394 case BackgroundVirtualPixelMethod:
5395 {
5396 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
5397 ((image->alpha_trait & BlendPixelTrait) == 0))
5398 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5399 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
5400 (IsGrayColorspace(image->colorspace) != MagickFalse))
5401 (void) SetImageColorspace(image,sRGBColorspace,exception);
5402 break;
5403 }
5404 case TransparentVirtualPixelMethod:
5405 {
5406 if ((image->alpha_trait & BlendPixelTrait) == 0)
5407 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5408 break;
5409 }
5410 default:
5411 break;
5412 }
5413 return(method);
5414}
5415
5416#if defined(MAGICKCORE_OPENCL_SUPPORT)
5417/*
5418%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5419% %
5420% %
5421% %
5422+ 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 %
5423% %
5424% %
5425% %
5426%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5427%
5428% SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
5429% been completed and updates the host memory.
5430%
5431% The format of the SyncAuthenticOpenCLBuffer() method is:
5432%
5433% void SyncAuthenticOpenCLBuffer(const Image *image)
5434%
5435% A description of each parameter follows:
5436%
5437% o image: the image.
5438%
5439*/
5440
5441static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5442{
5443 assert(cache_info != (CacheInfo *) NULL);
5444 assert(cache_info->signature == MagickCoreSignature);
5445 if ((cache_info->type != MemoryCache) ||
5446 (cache_info->opencl == (MagickCLCacheInfo) NULL))
5447 return;
5448 /*
5449 Ensure single threaded access to OpenCL environment.
5450 */
5451 LockSemaphoreInfo(cache_info->semaphore);
5452 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
5453 UnlockSemaphoreInfo(cache_info->semaphore);
5454}
5455
5456MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5457{
5458 CacheInfo
5459 *magick_restrict cache_info;
5460
5461 assert(image != (const Image *) NULL);
5462 cache_info=(CacheInfo *) image->cache;
5463 CopyOpenCLBuffer(cache_info);
5464}
5465#endif
5466
5467/*
5468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5469% %
5470% %
5471% %
5472+ 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 %
5473% %
5474% %
5475% %
5476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5477%
5478% SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5479% in-memory or disk cache. The method returns MagickTrue if the pixel region
5480% is synced, otherwise MagickFalse.
5481%
5482% The format of the SyncAuthenticPixelCacheNexus() method is:
5483%
5484% MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5485% NexusInfo *nexus_info,ExceptionInfo *exception)
5486%
5487% A description of each parameter follows:
5488%
5489% o image: the image.
5490%
5491% o nexus_info: the cache nexus to sync.
5492%
5493% o exception: return any errors or warnings in this structure.
5494%
5495*/
5496MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5497 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5498{
5499 CacheInfo
5500 *magick_restrict cache_info;
5501
5502 MagickBooleanType
5503 status;
5504
5505 /*
5506 Transfer pixels to the cache.
5507 */
5508 assert(image != (Image *) NULL);
5509 assert(image->signature == MagickCoreSignature);
5510 if (image->cache == (Cache) NULL)
5511 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5512 cache_info=(CacheInfo *) image->cache;
5513 assert(cache_info->signature == MagickCoreSignature);
5514 if (cache_info->type == UndefinedCache)
5515 return(MagickFalse);
5516 if (image->mask_trait != UpdatePixelTrait)
5517 {
5518 if (((image->channels & WriteMaskChannel) != 0) &&
5519 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5520 return(MagickFalse);
5521 if (((image->channels & CompositeMaskChannel) != 0) &&
5522 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5523 return(MagickFalse);
5524 }
5525 if (nexus_info->authentic_pixel_cache != MagickFalse)
5526 {
5527 if (image->taint == MagickFalse)
5528 image->taint=MagickTrue;
5529 return(MagickTrue);
5530 }
5531 assert(cache_info->signature == MagickCoreSignature);
5532 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5533 if ((cache_info->metacontent_extent != 0) &&
5534 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5535 return(MagickFalse);
5536 if ((status != MagickFalse) && (image->taint == MagickFalse))
5537 image->taint=MagickTrue;
5538 return(status);
5539}
5540
5541/*
5542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5543% %
5544% %
5545% %
5546+ S y n c A u t h e n t i c P i x e l C a c h e %
5547% %
5548% %
5549% %
5550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5551%
5552% SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5553% or disk cache. The method returns MagickTrue if the pixel region is synced,
5554% otherwise MagickFalse.
5555%
5556% The format of the SyncAuthenticPixelsCache() method is:
5557%
5558% MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5559% ExceptionInfo *exception)
5560%
5561% A description of each parameter follows:
5562%
5563% o image: the image.
5564%
5565% o exception: return any errors or warnings in this structure.
5566%
5567*/
5568static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5569 ExceptionInfo *exception)
5570{
5571 CacheInfo
5572 *magick_restrict cache_info;
5573
5574 const int
5575 id = GetOpenMPThreadId();
5576
5577 MagickBooleanType
5578 status;
5579
5580 assert(image != (Image *) NULL);
5581 assert(image->signature == MagickCoreSignature);
5582 assert(image->cache != (Cache) NULL);
5583 cache_info=(CacheInfo *) image->cache;
5584 assert(cache_info->signature == MagickCoreSignature);
5585 assert(id < (int) cache_info->number_threads);
5586 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5587 exception);
5588 return(status);
5589}
5590
5591/*
5592%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5593% %
5594% %
5595% %
5596% S y n c A u t h e n t i c P i x e l s %
5597% %
5598% %
5599% %
5600%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5601%
5602% SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5603% The method returns MagickTrue if the pixel region is flushed, otherwise
5604% MagickFalse.
5605%
5606% The format of the SyncAuthenticPixels() method is:
5607%
5608% MagickBooleanType SyncAuthenticPixels(Image *image,
5609% ExceptionInfo *exception)
5610%
5611% A description of each parameter follows:
5612%
5613% o image: the image.
5614%
5615% o exception: return any errors or warnings in this structure.
5616%
5617*/
5618MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5619 ExceptionInfo *exception)
5620{
5621 CacheInfo
5622 *magick_restrict cache_info;
5623
5624 const int
5625 id = GetOpenMPThreadId();
5626
5627 MagickBooleanType
5628 status;
5629
5630 assert(image != (Image *) NULL);
5631 assert(image->signature == MagickCoreSignature);
5632 assert(image->cache != (Cache) NULL);
5633 cache_info=(CacheInfo *) image->cache;
5634 assert(cache_info->signature == MagickCoreSignature);
5635 if (cache_info->methods.sync_authentic_pixels_handler != (SyncAuthenticPixelsHandler) NULL)
5636 {
5637 status=cache_info->methods.sync_authentic_pixels_handler(image,
5638 exception);
5639 return(status);
5640 }
5641 assert(id < (int) cache_info->number_threads);
5642 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5643 exception);
5644 return(status);
5645}
5646
5647/*
5648%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5649% %
5650% %
5651% %
5652+ S y n c I m a g e P i x e l C a c h e %
5653% %
5654% %
5655% %
5656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5657%
5658% SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5659% The method returns MagickTrue if the pixel region is flushed, otherwise
5660% MagickFalse.
5661%
5662% The format of the SyncImagePixelCache() method is:
5663%
5664% MagickBooleanType SyncImagePixelCache(Image *image,
5665% ExceptionInfo *exception)
5666%
5667% A description of each parameter follows:
5668%
5669% o image: the image.
5670%
5671% o exception: return any errors or warnings in this structure.
5672%
5673*/
5674MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5675 ExceptionInfo *exception)
5676{
5677 CacheInfo
5678 *magick_restrict cache_info;
5679
5680 assert(image != (Image *) NULL);
5681 assert(exception != (ExceptionInfo *) NULL);
5682 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5683 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5684}
5685
5686/*
5687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5688% %
5689% %
5690% %
5691+ 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 %
5692% %
5693% %
5694% %
5695%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5696%
5697% WritePixelCacheMetacontent() writes the meta-content to the specified region
5698% of the pixel cache.
5699%
5700% The format of the WritePixelCacheMetacontent() method is:
5701%
5702% MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5703% NexusInfo *nexus_info,ExceptionInfo *exception)
5704%
5705% A description of each parameter follows:
5706%
5707% o cache_info: the pixel cache.
5708%
5709% o nexus_info: the cache nexus to write the meta-content.
5710%
5711% o exception: return any errors or warnings in this structure.
5712%
5713*/
5714static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5715 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5716{
5717 MagickOffsetType
5718 count,
5719 offset;
5720
5721 MagickSizeType
5722 extent,
5723 length;
5724
5725 const unsigned char
5726 *magick_restrict p;
5727
5728 ssize_t
5729 y;
5730
5731 size_t
5732 rows;
5733
5734 if (cache_info->metacontent_extent == 0)
5735 return(MagickFalse);
5736 if (nexus_info->authentic_pixel_cache != MagickFalse)
5737 return(MagickTrue);
5738 if (nexus_info->metacontent == (unsigned char *) NULL)
5739 return(MagickFalse);
5740 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
5741 return(MagickFalse);
5742 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
5743 nexus_info->region.x;
5744 length=(MagickSizeType) nexus_info->region.width*
5745 cache_info->metacontent_extent;
5746 extent=(MagickSizeType) length*nexus_info->region.height;
5747 rows=nexus_info->region.height;
5748 y=0;
5749 p=(unsigned char *) nexus_info->metacontent;
5750 switch (cache_info->type)
5751 {
5752 case MemoryCache:
5753 case MapCache:
5754 {
5755 unsigned char
5756 *magick_restrict q;
5757
5758 /*
5759 Write associated pixels to memory.
5760 */
5761 if ((cache_info->columns == nexus_info->region.width) &&
5762 (extent == (MagickSizeType) ((size_t) extent)))
5763 {
5764 length=extent;
5765 rows=1UL;
5766 }
5767 q=(unsigned char *) cache_info->metacontent+offset*
5768 (MagickOffsetType) cache_info->metacontent_extent;
5769 for (y=0; y < (ssize_t) rows; y++)
5770 {
5771 (void) memcpy(q,p,(size_t) length);
5772 p+=(ptrdiff_t) nexus_info->region.width*cache_info->metacontent_extent;
5773 q+=(ptrdiff_t) cache_info->columns*cache_info->metacontent_extent;
5774 }
5775 break;
5776 }
5777 case DiskCache:
5778 {
5779 /*
5780 Write associated pixels to disk.
5781 */
5782 LockSemaphoreInfo(cache_info->file_semaphore);
5783 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5784 {
5785 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5786 cache_info->cache_filename);
5787 UnlockSemaphoreInfo(cache_info->file_semaphore);
5788 return(MagickFalse);
5789 }
5790 if ((cache_info->columns == nexus_info->region.width) &&
5791 (extent <= MagickMaxBufferExtent))
5792 {
5793 length=extent;
5794 rows=1UL;
5795 }
5796 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5797 for (y=0; y < (ssize_t) rows; y++)
5798 {
5799 count=WritePixelCacheRegion(cache_info,cache_info->offset+
5800 (MagickOffsetType) extent*(MagickOffsetType)
5801 cache_info->number_channels*(MagickOffsetType) sizeof(Quantum)+offset*
5802 (MagickOffsetType) cache_info->metacontent_extent,length,
5803 (const unsigned char *) p);
5804 if (count != (MagickOffsetType) length)
5805 break;
5806 p+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
5807 offset+=(MagickOffsetType) cache_info->columns;
5808 }
5809 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5810 (void) ClosePixelCacheOnDisk(cache_info);
5811 UnlockSemaphoreInfo(cache_info->file_semaphore);
5812 break;
5813 }
5814 case DistributedCache:
5815 {
5816 RectangleInfo
5817 region;
5818
5819 /*
5820 Write metacontent to distributed cache.
5821 */
5822 LockSemaphoreInfo(cache_info->file_semaphore);
5823 region=nexus_info->region;
5824 if ((cache_info->columns != nexus_info->region.width) ||
5825 (extent > MagickMaxBufferExtent))
5826 region.height=1UL;
5827 else
5828 {
5829 length=extent;
5830 rows=1UL;
5831 }
5832 for (y=0; y < (ssize_t) rows; y++)
5833 {
5834 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5835 cache_info->server_info,&region,length,(const unsigned char *) p);
5836 if (count != (MagickOffsetType) length)
5837 break;
5838 p+=(ptrdiff_t) cache_info->metacontent_extent*nexus_info->region.width;
5839 region.y++;
5840 }
5841 UnlockSemaphoreInfo(cache_info->file_semaphore);
5842 break;
5843 }
5844 default:
5845 break;
5846 }
5847 if (y < (ssize_t) rows)
5848 {
5849 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5850 cache_info->cache_filename);
5851 return(MagickFalse);
5852 }
5853 if ((cache_info->debug != MagickFalse) &&
5854 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5855 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5856 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5857 nexus_info->region.width,(double) nexus_info->region.height,(double)
5858 nexus_info->region.x,(double) nexus_info->region.y);
5859 return(MagickTrue);
5860}
5861
5862/*
5863%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5864% %
5865% %
5866% %
5867+ W r i t e C a c h e P i x e l s %
5868% %
5869% %
5870% %
5871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5872%
5873% WritePixelCachePixels() writes image pixels to the specified region of the
5874% pixel cache.
5875%
5876% The format of the WritePixelCachePixels() method is:
5877%
5878% MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5879% NexusInfo *nexus_info,ExceptionInfo *exception)
5880%
5881% A description of each parameter follows:
5882%
5883% o cache_info: the pixel cache.
5884%
5885% o nexus_info: the cache nexus to write the pixels.
5886%
5887% o exception: return any errors or warnings in this structure.
5888%
5889*/
5890static MagickBooleanType WritePixelCachePixels(
5891 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5892 ExceptionInfo *exception)
5893{
5894 MagickOffsetType
5895 count,
5896 offset;
5897
5898 MagickSizeType
5899 extent,
5900 length;
5901
5902 const Quantum
5903 *magick_restrict p;
5904
5905 ssize_t
5906 y;
5907
5908 size_t
5909 rows;
5910
5911 if (nexus_info->authentic_pixel_cache != MagickFalse)
5912 return(MagickTrue);
5913 if (IsValidPixelOffset(nexus_info->region.y,cache_info->columns) == MagickFalse)
5914 return(MagickFalse);
5915 offset=nexus_info->region.y*(MagickOffsetType) cache_info->columns+
5916 nexus_info->region.x;
5917 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5918 sizeof(Quantum);
5919 extent=length*nexus_info->region.height;
5920 rows=nexus_info->region.height;
5921 y=0;
5922 p=nexus_info->pixels;
5923 switch (cache_info->type)
5924 {
5925 case MemoryCache:
5926 case MapCache:
5927 {
5928 Quantum
5929 *magick_restrict q;
5930
5931 /*
5932 Write pixels to memory.
5933 */
5934 if ((cache_info->columns == nexus_info->region.width) &&
5935 (extent == (MagickSizeType) ((size_t) extent)))
5936 {
5937 length=extent;
5938 rows=1UL;
5939 }
5940 q=cache_info->pixels+(MagickOffsetType) cache_info->number_channels*
5941 offset;
5942 for (y=0; y < (ssize_t) rows; y++)
5943 {
5944 (void) memcpy(q,p,(size_t) length);
5945 p+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
5946 q+=(ptrdiff_t) cache_info->number_channels*cache_info->columns;
5947 }
5948 break;
5949 }
5950 case DiskCache:
5951 {
5952 /*
5953 Write pixels to disk.
5954 */
5955 LockSemaphoreInfo(cache_info->file_semaphore);
5956 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5957 {
5958 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5959 cache_info->cache_filename);
5960 UnlockSemaphoreInfo(cache_info->file_semaphore);
5961 return(MagickFalse);
5962 }
5963 if ((cache_info->columns == nexus_info->region.width) &&
5964 (extent <= MagickMaxBufferExtent))
5965 {
5966 length=extent;
5967 rows=1UL;
5968 }
5969 for (y=0; y < (ssize_t) rows; y++)
5970 {
5971 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5972 (MagickOffsetType) cache_info->number_channels*(MagickOffsetType)
5973 sizeof(*p),length,(const unsigned char *) p);
5974 if (count != (MagickOffsetType) length)
5975 break;
5976 p+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
5977 offset+=(MagickOffsetType) cache_info->columns;
5978 }
5979 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5980 (void) ClosePixelCacheOnDisk(cache_info);
5981 UnlockSemaphoreInfo(cache_info->file_semaphore);
5982 break;
5983 }
5984 case DistributedCache:
5985 {
5986 RectangleInfo
5987 region;
5988
5989 /*
5990 Write pixels to distributed cache.
5991 */
5992 LockSemaphoreInfo(cache_info->file_semaphore);
5993 region=nexus_info->region;
5994 if ((cache_info->columns != nexus_info->region.width) ||
5995 (extent > MagickMaxBufferExtent))
5996 region.height=1UL;
5997 else
5998 {
5999 length=extent;
6000 rows=1UL;
6001 }
6002 for (y=0; y < (ssize_t) rows; y++)
6003 {
6004 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
6005 cache_info->server_info,&region,length,(const unsigned char *) p);
6006 if (count != (MagickOffsetType) length)
6007 break;
6008 p+=(ptrdiff_t) cache_info->number_channels*nexus_info->region.width;
6009 region.y++;
6010 }
6011 UnlockSemaphoreInfo(cache_info->file_semaphore);
6012 break;
6013 }
6014 default:
6015 break;
6016 }
6017 if (y < (ssize_t) rows)
6018 {
6019 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
6020 cache_info->cache_filename);
6021 return(MagickFalse);
6022 }
6023 if ((cache_info->debug != MagickFalse) &&
6024 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
6025 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
6026 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
6027 nexus_info->region.width,(double) nexus_info->region.height,(double)
6028 nexus_info->region.x,(double) nexus_info->region.y);
6029 return(MagickTrue);
6030}