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