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