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