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