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