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