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