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