2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % https://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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/policy.h"
65 #include "MagickCore/quantum.h"
66 #include "MagickCore/random_.h"
67 #include "MagickCore/registry.h"
68 #include "MagickCore/resource_.h"
69 #include "MagickCore/semaphore.h"
70 #include "MagickCore/splay-tree.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/thread-private.h"
74 #include "MagickCore/utility.h"
75 #include "MagickCore/utility-private.h"
76 #if defined(MAGICKCORE_ZLIB_DELEGATE)
83 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
84 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
85 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
90 typedef struct _MagickModulo
100 #if defined(__cplusplus) || defined(c_plusplus)
105 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
109 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
110 const ssize_t,const size_t,const size_t,ExceptionInfo *),
111 *GetVirtualPixelsCache(const Image *);
114 *GetVirtualMetacontentFromCache(const Image *);
116 static MagickBooleanType
117 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
119 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
120 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
121 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
122 OpenPixelCacheOnDisk(CacheInfo *,const MapMode),
123 ReadPixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict,
125 ReadPixelCacheMetacontent(CacheInfo *magick_restrict,
126 NexusInfo *magick_restrict,ExceptionInfo *),
127 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
128 WritePixelCachePixels(CacheInfo *magick_restrict,NexusInfo *magick_restrict,
130 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *magick_restrict,
134 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
135 const size_t,ExceptionInfo *),
136 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
137 const size_t,ExceptionInfo *),
138 *SetPixelCacheNexusPixels(const CacheInfo *,const MapMode,
139 const RectangleInfo *,NexusInfo *,ExceptionInfo *) magick_hot_spot;
141 #if defined(MAGICKCORE_OPENCL_SUPPORT)
143 CopyOpenCLBuffer(CacheInfo *magick_restrict);
146 #if defined(__cplusplus) || defined(c_plusplus)
154 *cache_semaphore = (SemaphoreInfo *) NULL;
157 cache_anonymous_memory = (-1);
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167 + A c q u i r e P i x e l C a c h e %
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173 % AcquirePixelCache() acquires a pixel cache.
175 % The format of the AcquirePixelCache() method is:
177 % Cache AcquirePixelCache(const size_t number_threads)
179 % A description of each parameter follows:
181 % o number_threads: the number of nexus threads.
184 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
187 *magick_restrict cache_info;
192 cache_info=(CacheInfo *) AcquireCriticalMemory(sizeof(*cache_info));
193 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
194 cache_info->type=UndefinedCache;
195 cache_info->mode=IOMode;
196 cache_info->colorspace=sRGBColorspace;
197 cache_info->file=(-1);
198 cache_info->id=GetMagickThreadId();
199 cache_info->number_threads=number_threads;
200 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
201 cache_info->number_threads=GetOpenMPMaximumThreads();
202 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
203 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
204 if (cache_info->number_threads == 0)
205 cache_info->number_threads=1;
206 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
207 if (cache_info->nexus_info == (NexusInfo **) NULL)
208 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
209 value=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
210 if (value != (const char *) NULL)
212 cache_info->synchronize=IsStringTrue(value);
213 value=DestroyString(value);
215 value=GetPolicyValue("cache:synchronize");
216 if (value != (const char *) NULL)
218 cache_info->synchronize=IsStringTrue(value);
219 value=DestroyString(value);
221 cache_info->semaphore=AcquireSemaphoreInfo();
222 cache_info->reference_count=1;
223 cache_info->file_semaphore=AcquireSemaphoreInfo();
224 cache_info->debug=IsEventLogging();
225 cache_info->signature=MagickCoreSignature;
226 return((Cache ) cache_info);
230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234 % A c q u i r e P i x e l C a c h e N e x u s %
238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
242 % The format of the AcquirePixelCacheNexus method is:
244 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
246 % A description of each parameter follows:
248 % o number_threads: the number of nexus threads.
251 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
254 **magick_restrict nexus_info;
259 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
260 number_threads,sizeof(*nexus_info)));
261 if (nexus_info == (NexusInfo **) NULL)
262 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
263 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
264 sizeof(**nexus_info));
265 if (nexus_info[0] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
268 for (i=0; i < (ssize_t) number_threads; i++)
270 nexus_info[i]=(&nexus_info[0][i]);
271 nexus_info[i]->signature=MagickCoreSignature;
277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
281 + A c q u i r e P i x e l C a c h e P i x e l s %
285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287 % AcquirePixelCachePixels() returns the pixels associated with the specified
290 % The format of the AcquirePixelCachePixels() method is:
292 % const void *AcquirePixelCachePixels(const Image *image,
293 % MagickSizeType *length,ExceptionInfo *exception)
295 % A description of each parameter follows:
297 % o image: the image.
299 % o length: the pixel cache length.
301 % o exception: return any errors or warnings in this structure.
304 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
305 MagickSizeType *length,ExceptionInfo *exception)
308 *magick_restrict cache_info;
310 assert(image != (const Image *) NULL);
311 assert(image->signature == MagickCoreSignature);
312 assert(exception != (ExceptionInfo *) NULL);
313 assert(exception->signature == MagickCoreSignature);
314 assert(image->cache != (Cache) NULL);
315 cache_info=(CacheInfo *) image->cache;
316 assert(cache_info->signature == MagickCoreSignature);
318 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
319 return((const void *) NULL);
320 *length=cache_info->length;
321 return((const void *) cache_info->pixels);
325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329 + C a c h e C o m p o n e n t G e n e s i s %
333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335 % CacheComponentGenesis() instantiates the cache component.
337 % The format of the CacheComponentGenesis method is:
339 % MagickBooleanType CacheComponentGenesis(void)
342 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
344 if (cache_semaphore == (SemaphoreInfo *) NULL)
345 cache_semaphore=AcquireSemaphoreInfo();
350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354 + C a c h e C o m p o n e n t T e r m i n u s %
358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
360 % CacheComponentTerminus() destroys the cache component.
362 % The format of the CacheComponentTerminus() method is:
364 % CacheComponentTerminus(void)
367 MagickPrivate void CacheComponentTerminus(void)
369 if (cache_semaphore == (SemaphoreInfo *) NULL)
370 ActivateSemaphoreInfo(&cache_semaphore);
371 /* no op-- nothing to destroy */
372 RelinquishSemaphoreInfo(&cache_semaphore);
376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380 + C l o n e P i x e l C a c h e %
384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 % ClonePixelCache() clones a pixel cache.
388 % The format of the ClonePixelCache() method is:
390 % Cache ClonePixelCache(const Cache cache)
392 % A description of each parameter follows:
394 % o cache: the pixel cache.
397 MagickPrivate Cache ClonePixelCache(const Cache cache)
400 *magick_restrict clone_info;
403 *magick_restrict cache_info;
405 assert(cache != NULL);
406 cache_info=(const CacheInfo *) cache;
407 assert(cache_info->signature == MagickCoreSignature);
408 if (cache_info->debug != MagickFalse)
409 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
410 cache_info->filename);
411 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
412 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
413 return((Cache ) clone_info);
417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
421 + C l o n e P i x e l C a c h e M e t h o d s %
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
430 % The format of the ClonePixelCacheMethods() method is:
432 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
434 % A description of each parameter follows:
436 % o clone: Specifies a pointer to a Cache structure.
438 % o cache: the pixel cache.
441 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
444 *magick_restrict cache_info,
445 *magick_restrict source_info;
447 assert(clone != (Cache) NULL);
448 source_info=(CacheInfo *) clone;
449 assert(source_info->signature == MagickCoreSignature);
450 if (source_info->debug != MagickFalse)
451 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
452 source_info->filename);
453 assert(cache != (Cache) NULL);
454 cache_info=(CacheInfo *) cache;
455 assert(cache_info->signature == MagickCoreSignature);
456 source_info->methods=cache_info->methods;
460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464 + 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 %
468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
470 % ClonePixelCacheRepository() clones the source pixel cache to the destination
473 % The format of the ClonePixelCacheRepository() method is:
475 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
476 % CacheInfo *source_info,ExceptionInfo *exception)
478 % A description of each parameter follows:
480 % o cache_info: the pixel cache.
482 % o source_info: the source pixel cache.
484 % o exception: return any errors or warnings in this structure.
488 static MagickBooleanType ClonePixelCacheOnDisk(
489 CacheInfo *magick_restrict cache_info,CacheInfo *magick_restrict clone_info)
507 Clone pixel cache on disk with identical morphology.
509 if ((OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) ||
510 (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse))
512 quantum=(size_t) MagickMaxBufferExtent;
513 if ((fstat(cache_info->file,&file_stats) == 0) && (file_stats.st_size > 0))
514 quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
515 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
516 if (buffer == (unsigned char *) NULL)
517 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
519 while ((count=read(cache_info->file,buffer,quantum)) > 0)
524 number_bytes=write(clone_info->file,buffer,(size_t) count);
525 if (number_bytes != count)
527 extent+=number_bytes;
529 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
530 if (extent != cache_info->length)
535 static MagickBooleanType ClonePixelCacheRepository(
536 CacheInfo *magick_restrict clone_info,CacheInfo *magick_restrict cache_info,
537 ExceptionInfo *exception)
539 #define MaxCacheThreads ((size_t) GetMagickResourceLimit(ThreadResource))
540 #define cache_number_threads(source,destination,chunk,multithreaded) \
541 num_threads((multithreaded) == 0 ? 1 : \
542 (((source)->type != MemoryCache) && \
543 ((source)->type != MapCache)) || \
544 (((destination)->type != MemoryCache) && \
545 ((destination)->type != MapCache)) ? \
546 MagickMax(MagickMin(GetMagickResourceLimit(ThreadResource),2),1) : \
547 MagickMax(MagickMin((ssize_t) GetMagickResourceLimit(ThreadResource),(ssize_t) (chunk)/256),1))
554 **magick_restrict cache_nexus,
555 **magick_restrict clone_nexus;
563 assert(cache_info != (CacheInfo *) NULL);
564 assert(clone_info != (CacheInfo *) NULL);
565 assert(exception != (ExceptionInfo *) NULL);
566 if (cache_info->type == PingCache)
568 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
569 if ((cache_info->columns == clone_info->columns) &&
570 (cache_info->rows == clone_info->rows) &&
571 (cache_info->number_channels == clone_info->number_channels) &&
572 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
573 (cache_info->metacontent_extent == clone_info->metacontent_extent))
576 Identical pixel cache morphology.
578 if (((cache_info->type == MemoryCache) ||
579 (cache_info->type == MapCache)) &&
580 ((clone_info->type == MemoryCache) ||
581 (clone_info->type == MapCache)))
583 (void) memcpy(clone_info->pixels,cache_info->pixels,
584 cache_info->number_channels*cache_info->columns*cache_info->rows*
585 sizeof(*cache_info->pixels));
586 if ((cache_info->metacontent_extent != 0) &&
587 (clone_info->metacontent_extent != 0))
588 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
589 cache_info->columns*cache_info->rows*
590 clone_info->metacontent_extent*sizeof(unsigned char));
593 if ((cache_info->type == DiskCache) && (clone_info->type == DiskCache))
594 return(ClonePixelCacheOnDisk(cache_info,clone_info));
597 Mismatched pixel cache morphology.
599 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
600 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
601 if ((cache_nexus == (NexusInfo **) NULL) ||
602 (clone_nexus == (NexusInfo **) NULL))
603 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
604 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
605 optimize=(cache_info->number_channels == clone_info->number_channels) &&
606 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
607 MagickTrue : MagickFalse;
608 length=(size_t) MagickMin(cache_info->number_channels*cache_info->columns,
609 clone_info->number_channels*clone_info->columns);
611 #if defined(MAGICKCORE_OPENMP_SUPPORT)
612 #pragma omp parallel for schedule(static,4) shared(status) \
613 cache_number_threads(cache_info,clone_info,cache_info->rows,1)
615 for (y=0; y < (ssize_t) cache_info->rows; y++)
618 id = GetOpenMPThreadId();
629 if (status == MagickFalse)
631 if (y >= (ssize_t) clone_info->rows)
633 region.width=cache_info->columns;
637 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
638 cache_nexus[id],exception);
639 if (pixels == (Quantum *) NULL)
641 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
642 if (status == MagickFalse)
644 region.width=clone_info->columns;
645 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
646 clone_nexus[id],exception);
647 if (pixels == (Quantum *) NULL)
649 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,(size_t)
650 clone_nexus[id]->length);
651 if (optimize != MagickFalse)
652 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
656 register const Quantum
663 Mismatched pixel channel map.
665 p=cache_nexus[id]->pixels;
666 q=clone_nexus[id]->pixels;
667 for (x=0; x < (ssize_t) cache_info->columns; x++)
672 if (x == (ssize_t) clone_info->columns)
674 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
682 channel=clone_info->channel_map[i].channel;
683 traits=cache_info->channel_map[channel].traits;
684 if (traits != UndefinedPixelTrait)
685 *q=*(p+cache_info->channel_map[channel].offset);
688 p+=cache_info->number_channels;
691 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
693 if ((cache_info->metacontent_extent != 0) &&
694 (clone_info->metacontent_extent != 0))
699 length=(size_t) MagickMin(cache_info->metacontent_extent,
700 clone_info->metacontent_extent);
701 #if defined(MAGICKCORE_OPENMP_SUPPORT)
702 #pragma omp parallel for schedule(static,4) shared(status) \
703 cache_number_threads(cache_info,clone_info,cache_info->rows,1)
705 for (y=0; y < (ssize_t) cache_info->rows; y++)
708 id = GetOpenMPThreadId();
716 if (status == MagickFalse)
718 if (y >= (ssize_t) clone_info->rows)
720 region.width=cache_info->columns;
724 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
725 cache_nexus[id],exception);
726 if (pixels == (Quantum *) NULL)
728 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
729 if (status == MagickFalse)
731 region.width=clone_info->columns;
732 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
733 clone_nexus[id],exception);
734 if (pixels == (Quantum *) NULL)
736 if ((clone_nexus[id]->metacontent != (void *) NULL) &&
737 (cache_nexus[id]->metacontent != (void *) NULL))
738 (void) memcpy(clone_nexus[id]->metacontent,
739 cache_nexus[id]->metacontent,length*sizeof(unsigned char));
740 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
743 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
744 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
745 if (cache_info->debug != MagickFalse)
748 message[MagickPathExtent];
750 (void) FormatLocaleString(message,MagickPathExtent,"%s => %s",
751 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
752 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
753 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
763 + D e s t r o y I m a g e P i x e l C a c h e %
767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
769 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
771 % The format of the DestroyImagePixelCache() method is:
773 % void DestroyImagePixelCache(Image *image)
775 % A description of each parameter follows:
777 % o image: the image.
780 static void DestroyImagePixelCache(Image *image)
782 assert(image != (Image *) NULL);
783 assert(image->signature == MagickCoreSignature);
784 if (image->debug != MagickFalse)
785 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
786 if (image->cache == (void *) NULL)
788 image->cache=DestroyPixelCache(image->cache);
792 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
796 + D e s t r o y I m a g e P i x e l s %
800 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
802 % DestroyImagePixels() deallocates memory associated with the pixel cache.
804 % The format of the DestroyImagePixels() method is:
806 % void DestroyImagePixels(Image *image)
808 % A description of each parameter follows:
810 % o image: the image.
813 MagickExport void DestroyImagePixels(Image *image)
816 *magick_restrict cache_info;
818 assert(image != (const Image *) NULL);
819 assert(image->signature == MagickCoreSignature);
820 if (image->debug != MagickFalse)
821 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
822 assert(image->cache != (Cache) NULL);
823 cache_info=(CacheInfo *) image->cache;
824 assert(cache_info->signature == MagickCoreSignature);
825 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
827 cache_info->methods.destroy_pixel_handler(image);
830 image->cache=DestroyPixelCache(image->cache);
834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
838 + D e s t r o y P i x e l C a c h e %
842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
844 % DestroyPixelCache() deallocates memory associated with the pixel cache.
846 % The format of the DestroyPixelCache() method is:
848 % Cache DestroyPixelCache(Cache cache)
850 % A description of each parameter follows:
852 % o cache: the pixel cache.
856 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
862 if (cache_info->file != -1)
864 status=close(cache_info->file);
865 cache_info->file=(-1);
866 RelinquishMagickResource(FileResource,1);
868 return(status == -1 ? MagickFalse : MagickTrue);
871 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
873 switch (cache_info->type)
877 #if defined(MAGICKCORE_OPENCL_SUPPORT)
878 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
880 cache_info->opencl=RelinquishMagickCLCacheInfo(cache_info->opencl,
882 cache_info->pixels=(Quantum *) NULL;
886 if (cache_info->mapped == MagickFalse)
887 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
890 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
891 RelinquishMagickResource(MemoryResource,cache_info->length);
896 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
897 cache_info->pixels=(Quantum *) NULL;
898 if ((cache_info->mode != ReadMode) && (cache_info->mode != PersistMode))
899 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
900 *cache_info->cache_filename='\0';
901 RelinquishMagickResource(MapResource,cache_info->length);
905 if (cache_info->file != -1)
906 (void) ClosePixelCacheOnDisk(cache_info);
907 if ((cache_info->mode != ReadMode) && (cache_info->mode != PersistMode))
908 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
909 *cache_info->cache_filename='\0';
910 RelinquishMagickResource(DiskResource,cache_info->length);
913 case DistributedCache:
915 *cache_info->cache_filename='\0';
916 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
917 cache_info->server_info);
923 cache_info->type=UndefinedCache;
924 cache_info->mapped=MagickFalse;
925 cache_info->metacontent=(void *) NULL;
928 MagickPrivate Cache DestroyPixelCache(Cache cache)
931 *magick_restrict cache_info;
933 assert(cache != (Cache) NULL);
934 cache_info=(CacheInfo *) cache;
935 assert(cache_info->signature == MagickCoreSignature);
936 if (cache_info->debug != MagickFalse)
937 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
938 cache_info->filename);
939 LockSemaphoreInfo(cache_info->semaphore);
940 cache_info->reference_count--;
941 if (cache_info->reference_count != 0)
943 UnlockSemaphoreInfo(cache_info->semaphore);
944 return((Cache) NULL);
946 UnlockSemaphoreInfo(cache_info->semaphore);
947 if (cache_info->debug != MagickFalse)
950 message[MagickPathExtent];
952 (void) FormatLocaleString(message,MagickPathExtent,"destroy %s",
953 cache_info->filename);
954 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
956 RelinquishPixelCachePixels(cache_info);
957 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
958 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
959 cache_info->server_info);
960 if (cache_info->nexus_info != (NexusInfo **) NULL)
961 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
962 cache_info->number_threads);
963 if (cache_info->random_info != (RandomInfo *) NULL)
964 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
965 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
966 RelinquishSemaphoreInfo(&cache_info->file_semaphore);
967 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
968 RelinquishSemaphoreInfo(&cache_info->semaphore);
969 cache_info->signature=(~MagickCoreSignature);
970 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
980 + D e s t r o y P i x e l C a c h e N e x u s %
984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
988 % The format of the DestroyPixelCacheNexus() method is:
990 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
991 % const size_t number_threads)
993 % A description of each parameter follows:
995 % o nexus_info: the nexus to destroy.
997 % o number_threads: the number of nexus threads.
1001 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1003 if (nexus_info->mapped == MagickFalse)
1004 (void) RelinquishAlignedMemory(nexus_info->cache);
1006 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1007 nexus_info->cache=(Quantum *) NULL;
1008 nexus_info->pixels=(Quantum *) NULL;
1009 nexus_info->metacontent=(void *) NULL;
1010 nexus_info->length=0;
1011 nexus_info->mapped=MagickFalse;
1014 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1015 const size_t number_threads)
1020 assert(nexus_info != (NexusInfo **) NULL);
1021 for (i=0; i < (ssize_t) number_threads; i++)
1023 if (nexus_info[i]->cache != (Quantum *) NULL)
1024 RelinquishCacheNexusPixels(nexus_info[i]);
1025 nexus_info[i]->signature=(~MagickCoreSignature);
1027 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1028 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1037 % G e t A u t h e n t i c M e t a c o n t e n t %
1041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1043 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1044 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1045 % returned if the associated pixels are not available.
1047 % The format of the GetAuthenticMetacontent() method is:
1049 % void *GetAuthenticMetacontent(const Image *image)
1051 % A description of each parameter follows:
1053 % o image: the image.
1056 MagickExport void *GetAuthenticMetacontent(const Image *image)
1059 *magick_restrict cache_info;
1062 id = GetOpenMPThreadId();
1064 assert(image != (const Image *) NULL);
1065 assert(image->signature == MagickCoreSignature);
1066 assert(image->cache != (Cache) NULL);
1067 cache_info=(CacheInfo *) image->cache;
1068 assert(cache_info->signature == MagickCoreSignature);
1069 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1070 (GetAuthenticMetacontentFromHandler) NULL)
1075 metacontent=cache_info->methods.
1076 get_authentic_metacontent_from_handler(image);
1077 return(metacontent);
1079 assert(id < (int) cache_info->number_threads);
1080 return(cache_info->nexus_info[id]->metacontent);
1084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088 + 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 %
1092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1094 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1095 % with the last call to QueueAuthenticPixelsCache() or
1096 % GetAuthenticPixelsCache().
1098 % The format of the GetAuthenticMetacontentFromCache() method is:
1100 % void *GetAuthenticMetacontentFromCache(const Image *image)
1102 % A description of each parameter follows:
1104 % o image: the image.
1107 static void *GetAuthenticMetacontentFromCache(const Image *image)
1110 *magick_restrict cache_info;
1113 id = GetOpenMPThreadId();
1115 assert(image != (const Image *) NULL);
1116 assert(image->signature == MagickCoreSignature);
1117 assert(image->cache != (Cache) NULL);
1118 cache_info=(CacheInfo *) image->cache;
1119 assert(cache_info->signature == MagickCoreSignature);
1120 assert(id < (int) cache_info->number_threads);
1121 return(cache_info->nexus_info[id]->metacontent);
1124 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1130 + G e t A u t h e n t i c O p e n C L B u f f e r %
1134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1136 % GetAuthenticOpenCLBuffer() returns an OpenCL buffer used to execute OpenCL
1139 % The format of the GetAuthenticOpenCLBuffer() method is:
1141 % cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1142 % MagickCLDevice device,ExceptionInfo *exception)
1144 % A description of each parameter follows:
1146 % o image: the image.
1148 % o device: the device to use.
1150 % o exception: return any errors or warnings in this structure.
1153 MagickPrivate cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1154 MagickCLDevice device,ExceptionInfo *exception)
1157 *magick_restrict cache_info;
1159 assert(image != (const Image *) NULL);
1160 assert(device != (const MagickCLDevice) NULL);
1161 cache_info=(CacheInfo *) image->cache;
1162 if (cache_info->type == UndefinedCache)
1163 SyncImagePixelCache((Image *) image,exception);
1164 if ((cache_info->type != MemoryCache) || (cache_info->mapped != MagickFalse))
1165 return((cl_mem) NULL);
1166 LockSemaphoreInfo(cache_info->semaphore);
1167 if ((cache_info->opencl != (MagickCLCacheInfo) NULL) &&
1168 (cache_info->opencl->device->context != device->context))
1169 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
1170 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1172 assert(cache_info->pixels != (Quantum *) NULL);
1173 cache_info->opencl=AcquireMagickCLCacheInfo(device,cache_info->pixels,
1174 cache_info->length);
1176 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
1177 RetainOpenCLMemObject(cache_info->opencl->buffer);
1178 UnlockSemaphoreInfo(cache_info->semaphore);
1179 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1180 return((cl_mem) NULL);
1181 assert(cache_info->opencl->pixels == cache_info->pixels);
1182 return(cache_info->opencl->buffer);
1187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191 + 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 %
1195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1197 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1198 % disk pixel cache as defined by the geometry parameters. A pointer to the
1199 % pixels is returned if the pixels are transferred, otherwise a NULL is
1202 % The format of the GetAuthenticPixelCacheNexus() method is:
1204 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1205 % const ssize_t y,const size_t columns,const size_t rows,
1206 % NexusInfo *nexus_info,ExceptionInfo *exception)
1208 % A description of each parameter follows:
1210 % o image: the image.
1212 % o x,y,columns,rows: These values define the perimeter of a region of
1215 % o nexus_info: the cache nexus to return.
1217 % o exception: return any errors or warnings in this structure.
1221 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1222 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1223 ExceptionInfo *exception)
1226 *magick_restrict cache_info;
1229 *magick_restrict pixels;
1232 Transfer pixels from the cache.
1234 assert(image != (Image *) NULL);
1235 assert(image->signature == MagickCoreSignature);
1236 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1237 nexus_info,exception);
1238 if (pixels == (Quantum *) NULL)
1239 return((Quantum *) NULL);
1240 cache_info=(CacheInfo *) image->cache;
1241 assert(cache_info->signature == MagickCoreSignature);
1242 if (nexus_info->authentic_pixel_cache != MagickFalse)
1244 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1245 return((Quantum *) NULL);
1246 if (cache_info->metacontent_extent != 0)
1247 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1248 return((Quantum *) NULL);
1253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1257 + 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 %
1261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1263 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1264 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1266 % The format of the GetAuthenticPixelsFromCache() method is:
1268 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1270 % A description of each parameter follows:
1272 % o image: the image.
1275 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1278 *magick_restrict cache_info;
1281 id = GetOpenMPThreadId();
1283 assert(image != (const Image *) NULL);
1284 assert(image->signature == MagickCoreSignature);
1285 assert(image->cache != (Cache) NULL);
1286 cache_info=(CacheInfo *) image->cache;
1287 assert(cache_info->signature == MagickCoreSignature);
1288 assert(id < (int) cache_info->number_threads);
1289 return(cache_info->nexus_info[id]->pixels);
1293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1297 % G e t A u t h e n t i c P i x e l Q u e u e %
1301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 % GetAuthenticPixelQueue() returns the authentic pixels associated
1304 % corresponding with the last call to QueueAuthenticPixels() or
1305 % GetAuthenticPixels().
1307 % The format of the GetAuthenticPixelQueue() method is:
1309 % Quantum *GetAuthenticPixelQueue(const Image image)
1311 % A description of each parameter follows:
1313 % o image: the image.
1316 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1319 *magick_restrict cache_info;
1322 id = GetOpenMPThreadId();
1324 assert(image != (const Image *) NULL);
1325 assert(image->signature == MagickCoreSignature);
1326 assert(image->cache != (Cache) NULL);
1327 cache_info=(CacheInfo *) image->cache;
1328 assert(cache_info->signature == MagickCoreSignature);
1329 if (cache_info->methods.get_authentic_pixels_from_handler !=
1330 (GetAuthenticPixelsFromHandler) NULL)
1331 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1332 assert(id < (int) cache_info->number_threads);
1333 return(cache_info->nexus_info[id]->pixels);
1337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1341 % G e t A u t h e n t i c P i x e l s %
1345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1348 % region is successfully accessed, a pointer to a Quantum array
1349 % representing the region is returned, otherwise NULL is returned.
1351 % The returned pointer may point to a temporary working copy of the pixels
1352 % or it may point to the original pixels in memory. Performance is maximized
1353 % if the selected region is part of one row, or one or more full rows, since
1354 % then there is opportunity to access the pixels in-place (without a copy)
1355 % if the image is in memory, or in a memory-mapped file. The returned pointer
1356 % must *never* be deallocated by the user.
1358 % Pixels accessed via the returned pointer represent a simple array of type
1359 % Quantum. If the image has corresponding metacontent,call
1360 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1361 % meta-content corresponding to the region. Once the Quantum array has
1362 % been updated, the changes must be saved back to the underlying image using
1363 % SyncAuthenticPixels() or they may be lost.
1365 % The format of the GetAuthenticPixels() method is:
1367 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1368 % const ssize_t y,const size_t columns,const size_t rows,
1369 % ExceptionInfo *exception)
1371 % A description of each parameter follows:
1373 % o image: the image.
1375 % o x,y,columns,rows: These values define the perimeter of a region of
1378 % o exception: return any errors or warnings in this structure.
1381 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1382 const ssize_t y,const size_t columns,const size_t rows,
1383 ExceptionInfo *exception)
1386 *magick_restrict cache_info;
1389 id = GetOpenMPThreadId();
1394 assert(image != (Image *) NULL);
1395 assert(image->signature == MagickCoreSignature);
1396 assert(image->cache != (Cache) NULL);
1397 cache_info=(CacheInfo *) image->cache;
1398 assert(cache_info->signature == MagickCoreSignature);
1399 if (cache_info->methods.get_authentic_pixels_handler !=
1400 (GetAuthenticPixelsHandler) NULL)
1402 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1406 assert(id < (int) cache_info->number_threads);
1407 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1408 cache_info->nexus_info[id],exception);
1413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1417 + G e t A u t h e n t i c P i x e l s C a c h e %
1421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1424 % as defined by the geometry parameters. A pointer to the pixels is returned
1425 % if the pixels are transferred, otherwise a NULL is returned.
1427 % The format of the GetAuthenticPixelsCache() method is:
1429 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1430 % const ssize_t y,const size_t columns,const size_t rows,
1431 % ExceptionInfo *exception)
1433 % A description of each parameter follows:
1435 % o image: the image.
1437 % o x,y,columns,rows: These values define the perimeter of a region of
1440 % o exception: return any errors or warnings in this structure.
1443 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1444 const ssize_t y,const size_t columns,const size_t rows,
1445 ExceptionInfo *exception)
1448 *magick_restrict cache_info;
1451 id = GetOpenMPThreadId();
1454 *magick_restrict pixels;
1456 assert(image != (const Image *) NULL);
1457 assert(image->signature == MagickCoreSignature);
1458 assert(image->cache != (Cache) NULL);
1459 cache_info=(CacheInfo *) image->cache;
1460 if (cache_info == (Cache) NULL)
1461 return((Quantum *) NULL);
1462 assert(cache_info->signature == MagickCoreSignature);
1463 assert(id < (int) cache_info->number_threads);
1464 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1465 cache_info->nexus_info[id],exception);
1470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1474 + G e t I m a g e E x t e n t %
1478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480 % GetImageExtent() returns the extent of the pixels associated corresponding
1481 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1483 % The format of the GetImageExtent() method is:
1485 % MagickSizeType GetImageExtent(const Image *image)
1487 % A description of each parameter follows:
1489 % o image: the image.
1492 MagickExport MagickSizeType GetImageExtent(const Image *image)
1495 *magick_restrict cache_info;
1498 id = GetOpenMPThreadId();
1500 assert(image != (Image *) NULL);
1501 assert(image->signature == MagickCoreSignature);
1502 if (image->debug != MagickFalse)
1503 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1504 assert(image->cache != (Cache) NULL);
1505 cache_info=(CacheInfo *) image->cache;
1506 assert(cache_info->signature == MagickCoreSignature);
1507 assert(id < (int) cache_info->number_threads);
1508 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1516 + G e t I m a g e P i x e l C a c h e %
1520 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522 % GetImagePixelCache() ensures that there is only a single reference to the
1523 % pixel cache to be modified, updating the provided cache pointer to point to
1524 % a clone of the original pixel cache if necessary.
1526 % The format of the GetImagePixelCache method is:
1528 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1529 % ExceptionInfo *exception)
1531 % A description of each parameter follows:
1533 % o image: the image.
1535 % o clone: any value other than MagickFalse clones the cache pixels.
1537 % o exception: return any errors or warnings in this structure.
1541 static inline MagickBooleanType ValidatePixelCacheMorphology(
1542 const Image *magick_restrict image)
1545 *magick_restrict cache_info;
1547 const PixelChannelMap
1552 Does the image match the pixel cache morphology?
1554 cache_info=(CacheInfo *) image->cache;
1555 p=image->channel_map;
1556 q=cache_info->channel_map;
1557 if ((image->storage_class != cache_info->storage_class) ||
1558 (image->colorspace != cache_info->colorspace) ||
1559 (image->alpha_trait != cache_info->alpha_trait) ||
1560 (image->read_mask != cache_info->read_mask) ||
1561 (image->write_mask != cache_info->write_mask) ||
1562 (image->columns != cache_info->columns) ||
1563 (image->rows != cache_info->rows) ||
1564 (image->number_channels != cache_info->number_channels) ||
1565 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1566 (image->metacontent_extent != cache_info->metacontent_extent) ||
1567 (cache_info->nexus_info == (NexusInfo **) NULL))
1568 return(MagickFalse);
1572 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1573 ExceptionInfo *exception)
1576 *magick_restrict cache_info;
1582 static MagickSizeType
1583 cache_timelimit = MagickResourceInfinity,
1584 cpu_throttle = MagickResourceInfinity,
1588 if (cpu_throttle == MagickResourceInfinity)
1589 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1590 if ((cpu_throttle != 0) && ((cycles++ % 32) == 0))
1591 MagickDelay(cpu_throttle);
1592 if (cache_epoch == 0)
1595 Set the expire time in seconds.
1597 cache_timelimit=GetMagickResourceLimit(TimeResource);
1598 cache_epoch=time((time_t *) NULL);
1600 if ((cache_timelimit != MagickResourceInfinity) &&
1601 ((MagickSizeType) (time((time_t *) NULL)-cache_epoch) >= cache_timelimit))
1603 #if defined(ECANCELED)
1606 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1608 LockSemaphoreInfo(image->semaphore);
1609 assert(image->cache != (Cache) NULL);
1610 cache_info=(CacheInfo *) image->cache;
1611 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1612 CopyOpenCLBuffer(cache_info);
1614 destroy=MagickFalse;
1615 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1617 LockSemaphoreInfo(cache_info->semaphore);
1618 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1629 clone_image=(*image);
1630 clone_image.semaphore=AcquireSemaphoreInfo();
1631 clone_image.reference_count=1;
1632 clone_image.cache=ClonePixelCache(cache_info);
1633 clone_info=(CacheInfo *) clone_image.cache;
1634 status=OpenPixelCache(&clone_image,IOMode,exception);
1635 if (status != MagickFalse)
1637 if (clone != MagickFalse)
1638 status=ClonePixelCacheRepository(clone_info,cache_info,
1640 if (status != MagickFalse)
1643 image->cache=clone_image.cache;
1646 RelinquishSemaphoreInfo(&clone_image.semaphore);
1648 UnlockSemaphoreInfo(cache_info->semaphore);
1650 if (destroy != MagickFalse)
1651 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1652 if (status != MagickFalse)
1655 Ensure the image matches the pixel cache morphology.
1657 image->type=UndefinedType;
1658 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1660 status=OpenPixelCache(image,IOMode,exception);
1661 cache_info=(CacheInfo *) image->cache;
1662 if (cache_info->type == DiskCache)
1663 (void) ClosePixelCacheOnDisk(cache_info);
1666 UnlockSemaphoreInfo(image->semaphore);
1667 if (status == MagickFalse)
1668 return((Cache) NULL);
1669 return(image->cache);
1673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677 + G e t I m a g e P i x e l C a c h e T y p e %
1681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1683 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1684 % DiskCache, MemoryCache, MapCache, or PingCache.
1686 % The format of the GetImagePixelCacheType() method is:
1688 % CacheType GetImagePixelCacheType(const Image *image)
1690 % A description of each parameter follows:
1692 % o image: the image.
1695 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1698 *magick_restrict cache_info;
1700 assert(image != (Image *) NULL);
1701 assert(image->signature == MagickCoreSignature);
1702 assert(image->cache != (Cache) NULL);
1703 cache_info=(CacheInfo *) image->cache;
1704 assert(cache_info->signature == MagickCoreSignature);
1705 return(cache_info->type);
1709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1713 % G e t O n e A u t h e n t i c P i x e l %
1717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1719 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1720 % location. The image background color is returned if an error occurs.
1722 % The format of the GetOneAuthenticPixel() method is:
1724 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1725 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1727 % A description of each parameter follows:
1729 % o image: the image.
1731 % o x,y: These values define the location of the pixel to return.
1733 % o pixel: return a pixel at the specified (x,y) location.
1735 % o exception: return any errors or warnings in this structure.
1739 static inline MagickBooleanType CopyPixel(const Image *image,
1740 const Quantum *source,Quantum *destination)
1745 if (source == (const Quantum *) NULL)
1747 destination[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1748 destination[GreenPixelChannel]=ClampToQuantum(
1749 image->background_color.green);
1750 destination[BluePixelChannel]=ClampToQuantum(
1751 image->background_color.blue);
1752 destination[BlackPixelChannel]=ClampToQuantum(
1753 image->background_color.black);
1754 destination[AlphaPixelChannel]=ClampToQuantum(
1755 image->background_color.alpha);
1756 return(MagickFalse);
1758 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1760 PixelChannel channel = GetPixelChannelChannel(image,i);
1761 destination[channel]=source[i];
1766 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1767 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1770 *magick_restrict cache_info;
1775 assert(image != (Image *) NULL);
1776 assert(image->signature == MagickCoreSignature);
1777 assert(image->cache != (Cache) NULL);
1778 cache_info=(CacheInfo *) image->cache;
1779 assert(cache_info->signature == MagickCoreSignature);
1780 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1781 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1782 (GetOneAuthenticPixelFromHandler) NULL)
1783 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1785 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1786 return(CopyPixel(image,q,pixel));
1790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1794 + 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 %
1798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1800 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1801 % location. The image background color is returned if an error occurs.
1803 % The format of the GetOneAuthenticPixelFromCache() method is:
1805 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1806 % const ssize_t x,const ssize_t y,Quantum *pixel,
1807 % ExceptionInfo *exception)
1809 % A description of each parameter follows:
1811 % o image: the image.
1813 % o x,y: These values define the location of the pixel to return.
1815 % o pixel: return a pixel at the specified (x,y) location.
1817 % o exception: return any errors or warnings in this structure.
1820 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1821 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1824 *magick_restrict cache_info;
1827 id = GetOpenMPThreadId();
1832 assert(image != (const Image *) NULL);
1833 assert(image->signature == MagickCoreSignature);
1834 assert(image->cache != (Cache) NULL);
1835 cache_info=(CacheInfo *) image->cache;
1836 assert(cache_info->signature == MagickCoreSignature);
1837 assert(id < (int) cache_info->number_threads);
1838 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1839 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1841 return(CopyPixel(image,q,pixel));
1845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1849 % G e t O n e V i r t u a l P i x e l %
1853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1855 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1856 % (x,y) location. The image background color is returned if an error occurs.
1857 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1859 % The format of the GetOneVirtualPixel() method is:
1861 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1862 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1864 % A description of each parameter follows:
1866 % o image: the image.
1868 % o x,y: These values define the location of the pixel to return.
1870 % o pixel: return a pixel at the specified (x,y) location.
1872 % o exception: return any errors or warnings in this structure.
1875 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1876 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1879 *magick_restrict cache_info;
1882 id = GetOpenMPThreadId();
1887 assert(image != (const Image *) NULL);
1888 assert(image->signature == MagickCoreSignature);
1889 assert(image->cache != (Cache) NULL);
1890 cache_info=(CacheInfo *) image->cache;
1891 assert(cache_info->signature == MagickCoreSignature);
1892 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1893 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1894 (GetOneVirtualPixelFromHandler) NULL)
1895 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1896 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1897 assert(id < (int) cache_info->number_threads);
1898 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1899 1UL,1UL,cache_info->nexus_info[id],exception);
1900 return(CopyPixel(image,p,pixel));
1904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1908 + 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 %
1912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1914 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1915 % specified (x,y) location. The image background color is returned if an
1918 % The format of the GetOneVirtualPixelFromCache() method is:
1920 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1921 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1922 % Quantum *pixel,ExceptionInfo *exception)
1924 % A description of each parameter follows:
1926 % o image: the image.
1928 % o virtual_pixel_method: the virtual pixel method.
1930 % o x,y: These values define the location of the pixel to return.
1932 % o pixel: return a pixel at the specified (x,y) location.
1934 % o exception: return any errors or warnings in this structure.
1937 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1938 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1939 Quantum *pixel,ExceptionInfo *exception)
1942 *magick_restrict cache_info;
1945 id = GetOpenMPThreadId();
1950 assert(image != (const Image *) NULL);
1951 assert(image->signature == MagickCoreSignature);
1952 assert(image->cache != (Cache) NULL);
1953 cache_info=(CacheInfo *) image->cache;
1954 assert(cache_info->signature == MagickCoreSignature);
1955 assert(id < (int) cache_info->number_threads);
1956 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1957 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1958 cache_info->nexus_info[id],exception);
1959 return(CopyPixel(image,p,pixel));
1963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1967 % G e t O n e V i r t u a l P i x e l I n f o %
1971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1973 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1974 % location. The image background color is returned if an error occurs. If
1975 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1977 % The format of the GetOneVirtualPixelInfo() method is:
1979 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1980 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1981 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1983 % A description of each parameter follows:
1985 % o image: the image.
1987 % o virtual_pixel_method: the virtual pixel method.
1989 % o x,y: these values define the location of the pixel to return.
1991 % o pixel: return a pixel at the specified (x,y) location.
1993 % o exception: return any errors or warnings in this structure.
1996 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
1997 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1998 PixelInfo *pixel,ExceptionInfo *exception)
2001 *magick_restrict cache_info;
2004 id = GetOpenMPThreadId();
2006 register const Quantum
2009 assert(image != (const Image *) NULL);
2010 assert(image->signature == MagickCoreSignature);
2011 assert(image->cache != (Cache) NULL);
2012 cache_info=(CacheInfo *) image->cache;
2013 assert(cache_info->signature == MagickCoreSignature);
2014 assert(id < (int) cache_info->number_threads);
2015 GetPixelInfo(image,pixel);
2016 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2017 cache_info->nexus_info[id],exception);
2018 if (p == (const Quantum *) NULL)
2019 return(MagickFalse);
2020 GetPixelInfoPixel(image,p,pixel);
2025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2029 + G e t P i x e l C a c h e C o l o r s p a c e %
2033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2035 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2037 % The format of the GetPixelCacheColorspace() method is:
2039 % Colorspace GetPixelCacheColorspace(Cache cache)
2041 % A description of each parameter follows:
2043 % o cache: the pixel cache.
2046 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2049 *magick_restrict cache_info;
2051 assert(cache != (Cache) NULL);
2052 cache_info=(CacheInfo *) cache;
2053 assert(cache_info->signature == MagickCoreSignature);
2054 if (cache_info->debug != MagickFalse)
2055 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2056 cache_info->filename);
2057 return(cache_info->colorspace);
2061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2065 + G e t P i x e l C a c h e F i l e n a m e %
2069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2071 % GetPixelCacheFilename() returns the filename associated with the pixel
2074 % The format of the GetPixelCacheFilename() method is:
2076 % const char *GetPixelCacheFilename(const Image *image)
2078 % A description of each parameter follows:
2080 % o image: the image.
2083 MagickExport const char *GetPixelCacheFilename(const Image *image)
2086 *magick_restrict cache_info;
2088 assert(image != (const Image *) NULL);
2089 assert(image->signature == MagickCoreSignature);
2090 assert(image->cache != (Cache) NULL);
2091 cache_info=(CacheInfo *) image->cache;
2092 assert(cache_info->signature == MagickCoreSignature);
2093 return(cache_info->cache_filename);
2097 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2101 + G e t P i x e l C a c h e M e t h o d s %
2105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2107 % GetPixelCacheMethods() initializes the CacheMethods structure.
2109 % The format of the GetPixelCacheMethods() method is:
2111 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2113 % A description of each parameter follows:
2115 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2118 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2120 assert(cache_methods != (CacheMethods *) NULL);
2121 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2122 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2123 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2124 cache_methods->get_virtual_metacontent_from_handler=
2125 GetVirtualMetacontentFromCache;
2126 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2127 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2128 cache_methods->get_authentic_metacontent_from_handler=
2129 GetAuthenticMetacontentFromCache;
2130 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2131 cache_methods->get_one_authentic_pixel_from_handler=
2132 GetOneAuthenticPixelFromCache;
2133 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2134 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2135 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2143 + G e t P i x e l C a c h e N e x u s E x t e n t %
2147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2149 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2150 % corresponding with the last call to SetPixelCacheNexusPixels() or
2151 % GetPixelCacheNexusPixels().
2153 % The format of the GetPixelCacheNexusExtent() method is:
2155 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2156 % NexusInfo *nexus_info)
2158 % A description of each parameter follows:
2160 % o nexus_info: the nexus info.
2163 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2164 NexusInfo *magick_restrict nexus_info)
2167 *magick_restrict cache_info;
2172 assert(cache != NULL);
2173 cache_info=(CacheInfo *) cache;
2174 assert(cache_info->signature == MagickCoreSignature);
2175 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2177 return((MagickSizeType) cache_info->columns*cache_info->rows);
2182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2186 + G e t P i x e l C a c h e P i x e l s %
2190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2192 % GetPixelCachePixels() returns the pixels associated with the specified image.
2194 % The format of the GetPixelCachePixels() method is:
2196 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2197 % ExceptionInfo *exception)
2199 % A description of each parameter follows:
2201 % o image: the image.
2203 % o length: the pixel cache length.
2205 % o exception: return any errors or warnings in this structure.
2208 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2209 ExceptionInfo *exception)
2212 *magick_restrict cache_info;
2214 assert(image != (const Image *) NULL);
2215 assert(image->signature == MagickCoreSignature);
2216 assert(image->cache != (Cache) NULL);
2217 assert(length != (MagickSizeType *) NULL);
2218 assert(exception != (ExceptionInfo *) NULL);
2219 assert(exception->signature == MagickCoreSignature);
2220 cache_info=(CacheInfo *) image->cache;
2221 assert(cache_info->signature == MagickCoreSignature);
2222 *length=cache_info->length;
2223 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2224 return((void *) NULL);
2225 return((void *) cache_info->pixels);
2229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2233 + 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 %
2237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2239 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2241 % The format of the GetPixelCacheStorageClass() method is:
2243 % ClassType GetPixelCacheStorageClass(Cache cache)
2245 % A description of each parameter follows:
2247 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2249 % o cache: the pixel cache.
2252 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2255 *magick_restrict cache_info;
2257 assert(cache != (Cache) NULL);
2258 cache_info=(CacheInfo *) cache;
2259 assert(cache_info->signature == MagickCoreSignature);
2260 if (cache_info->debug != MagickFalse)
2261 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2262 cache_info->filename);
2263 return(cache_info->storage_class);
2267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2271 + G e t P i x e l C a c h e T i l e S i z e %
2275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2277 % GetPixelCacheTileSize() returns the pixel cache tile size.
2279 % The format of the GetPixelCacheTileSize() method is:
2281 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2284 % A description of each parameter follows:
2286 % o image: the image.
2288 % o width: the optimized cache tile width in pixels.
2290 % o height: the optimized cache tile height in pixels.
2293 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2297 *magick_restrict cache_info;
2299 assert(image != (Image *) NULL);
2300 assert(image->signature == MagickCoreSignature);
2301 if (image->debug != MagickFalse)
2302 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2303 cache_info=(CacheInfo *) image->cache;
2304 assert(cache_info->signature == MagickCoreSignature);
2305 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2306 if (GetImagePixelCacheType(image) == DiskCache)
2307 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2316 + 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 %
2320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2322 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2323 % pixel cache. A virtual pixel is any pixel access that is outside the
2324 % boundaries of the image cache.
2326 % The format of the GetPixelCacheVirtualMethod() method is:
2328 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2330 % A description of each parameter follows:
2332 % o image: the image.
2335 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2338 *magick_restrict cache_info;
2340 assert(image != (Image *) NULL);
2341 assert(image->signature == MagickCoreSignature);
2342 assert(image->cache != (Cache) NULL);
2343 cache_info=(CacheInfo *) image->cache;
2344 assert(cache_info->signature == MagickCoreSignature);
2345 return(cache_info->virtual_pixel_method);
2349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2353 + 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 %
2357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2359 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2360 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2362 % The format of the GetVirtualMetacontentFromCache() method is:
2364 % void *GetVirtualMetacontentFromCache(const Image *image)
2366 % A description of each parameter follows:
2368 % o image: the image.
2371 static const void *GetVirtualMetacontentFromCache(const Image *image)
2374 *magick_restrict cache_info;
2377 id = GetOpenMPThreadId();
2380 *magick_restrict metacontent;
2382 assert(image != (const Image *) NULL);
2383 assert(image->signature == MagickCoreSignature);
2384 assert(image->cache != (Cache) NULL);
2385 cache_info=(CacheInfo *) image->cache;
2386 assert(cache_info->signature == MagickCoreSignature);
2387 assert(id < (int) cache_info->number_threads);
2388 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2389 cache_info->nexus_info[id]);
2390 return(metacontent);
2394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2398 + 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 %
2402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2404 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2407 % The format of the GetVirtualMetacontentFromNexus() method is:
2409 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2410 % NexusInfo *nexus_info)
2412 % A description of each parameter follows:
2414 % o cache: the pixel cache.
2416 % o nexus_info: the cache nexus to return the meta-content.
2419 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2420 NexusInfo *magick_restrict nexus_info)
2423 *magick_restrict cache_info;
2425 assert(cache != (Cache) NULL);
2426 cache_info=(CacheInfo *) cache;
2427 assert(cache_info->signature == MagickCoreSignature);
2428 if (cache_info->storage_class == UndefinedClass)
2429 return((void *) NULL);
2430 return(nexus_info->metacontent);
2434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2438 % G e t V i r t u a l M e t a c o n t e n t %
2442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2444 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2445 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2446 % returned if the meta-content are not available.
2448 % The format of the GetVirtualMetacontent() method is:
2450 % const void *GetVirtualMetacontent(const Image *image)
2452 % A description of each parameter follows:
2454 % o image: the image.
2457 MagickExport const void *GetVirtualMetacontent(const Image *image)
2460 *magick_restrict cache_info;
2463 id = GetOpenMPThreadId();
2466 *magick_restrict metacontent;
2468 assert(image != (const Image *) NULL);
2469 assert(image->signature == MagickCoreSignature);
2470 assert(image->cache != (Cache) NULL);
2471 cache_info=(CacheInfo *) image->cache;
2472 assert(cache_info->signature == MagickCoreSignature);
2473 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2474 if (metacontent != (void *) NULL)
2475 return(metacontent);
2476 assert(id < (int) cache_info->number_threads);
2477 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2478 cache_info->nexus_info[id]);
2479 return(metacontent);
2483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2487 + G e t V i r t u a l P i x e l s F r o m N e x u s %
2491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2493 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2494 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2495 % is returned if the pixels are transferred, otherwise a NULL is returned.
2497 % The format of the GetVirtualPixelsFromNexus() method is:
2499 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2500 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2501 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2502 % ExceptionInfo *exception)
2504 % A description of each parameter follows:
2506 % o image: the image.
2508 % o virtual_pixel_method: the virtual pixel method.
2510 % o x,y,columns,rows: These values define the perimeter of a region of
2513 % o nexus_info: the cache nexus to acquire.
2515 % o exception: return any errors or warnings in this structure.
2522 0, 48, 12, 60, 3, 51, 15, 63,
2523 32, 16, 44, 28, 35, 19, 47, 31,
2524 8, 56, 4, 52, 11, 59, 7, 55,
2525 40, 24, 36, 20, 43, 27, 39, 23,
2526 2, 50, 14, 62, 1, 49, 13, 61,
2527 34, 18, 46, 30, 33, 17, 45, 29,
2528 10, 58, 6, 54, 9, 57, 5, 53,
2529 42, 26, 38, 22, 41, 25, 37, 21
2532 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2537 index=x+DitherMatrix[x & 0x07]-32L;
2540 if (index >= (ssize_t) columns)
2541 return((ssize_t) columns-1L);
2545 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2550 index=y+DitherMatrix[y & 0x07]-32L;
2553 if (index >= (ssize_t) rows)
2554 return((ssize_t) rows-1L);
2558 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2562 if (x >= (ssize_t) columns)
2563 return((ssize_t) (columns-1));
2567 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2571 if (y >= (ssize_t) rows)
2572 return((ssize_t) (rows-1));
2576 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2578 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2581 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2583 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2586 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2587 const size_t extent)
2593 Compute the remainder of dividing offset by extent. It returns not only
2594 the quotient (tile the offset falls in) but also the positive remainer
2595 within that tile such that 0 <= remainder < extent. This method is
2596 essentially a ldiv() using a floored modulo division rather than the
2597 normal default truncated modulo division.
2599 modulo.quotient=offset/(ssize_t) extent;
2602 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2606 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2607 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2608 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2609 ExceptionInfo *exception)
2612 *magick_restrict cache_info;
2622 **magick_restrict virtual_nexus;
2625 *magick_restrict pixels,
2626 virtual_pixel[MaxPixelChannels];
2631 register const Quantum
2644 register unsigned char
2651 *magick_restrict virtual_metacontent;
2656 assert(image != (const Image *) NULL);
2657 assert(image->signature == MagickCoreSignature);
2658 assert(image->cache != (Cache) NULL);
2659 cache_info=(CacheInfo *) image->cache;
2660 assert(cache_info->signature == MagickCoreSignature);
2661 if (cache_info->type == UndefinedCache)
2662 return((const Quantum *) NULL);
2663 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2664 CopyOpenCLBuffer(cache_info);
2668 region.width=columns;
2670 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2672 if (pixels == (Quantum *) NULL)
2673 return((const Quantum *) NULL);
2675 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2676 nexus_info->region.x;
2677 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2678 nexus_info->region.width-1L;
2679 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2680 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2681 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2682 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2688 Pixel request is inside cache extents.
2690 if (nexus_info->authentic_pixel_cache != MagickFalse)
2692 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2693 if (status == MagickFalse)
2694 return((const Quantum *) NULL);
2695 if (cache_info->metacontent_extent != 0)
2697 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2698 if (status == MagickFalse)
2699 return((const Quantum *) NULL);
2704 Pixel request is outside cache extents.
2706 s=(unsigned char *) nexus_info->metacontent;
2707 virtual_nexus=AcquirePixelCacheNexus(1);
2708 if (virtual_nexus == (NexusInfo **) NULL)
2710 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2711 "UnableToGetCacheNexus","`%s'",image->filename);
2712 return((const Quantum *) NULL);
2714 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2715 sizeof(*virtual_pixel));
2716 virtual_metacontent=(void *) NULL;
2717 switch (virtual_pixel_method)
2719 case BackgroundVirtualPixelMethod:
2720 case BlackVirtualPixelMethod:
2721 case GrayVirtualPixelMethod:
2722 case TransparentVirtualPixelMethod:
2723 case MaskVirtualPixelMethod:
2724 case WhiteVirtualPixelMethod:
2725 case EdgeVirtualPixelMethod:
2726 case CheckerTileVirtualPixelMethod:
2727 case HorizontalTileVirtualPixelMethod:
2728 case VerticalTileVirtualPixelMethod:
2730 if (cache_info->metacontent_extent != 0)
2733 Acquire a metacontent buffer.
2735 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2736 cache_info->metacontent_extent);
2737 if (virtual_metacontent == (void *) NULL)
2739 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2740 (void) ThrowMagickException(exception,GetMagickModule(),
2741 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2742 return((const Quantum *) NULL);
2744 (void) ResetMagickMemory(virtual_metacontent,0,
2745 cache_info->metacontent_extent);
2747 switch (virtual_pixel_method)
2749 case BlackVirtualPixelMethod:
2751 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2752 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2753 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2756 case GrayVirtualPixelMethod:
2758 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2759 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2761 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2764 case TransparentVirtualPixelMethod:
2766 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2767 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2768 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2771 case MaskVirtualPixelMethod:
2772 case WhiteVirtualPixelMethod:
2774 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2775 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2776 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2781 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2783 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2785 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2787 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2789 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2799 for (v=0; v < (ssize_t) rows; v++)
2805 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2806 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2807 y_offset=EdgeY(y_offset,cache_info->rows);
2808 for (u=0; u < (ssize_t) columns; u+=length)
2814 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2815 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2816 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2824 Transfer a single pixel.
2826 length=(MagickSizeType) 1;
2827 switch (virtual_pixel_method)
2829 case EdgeVirtualPixelMethod:
2832 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2833 EdgeX(x_offset,cache_info->columns),
2834 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2836 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2839 case RandomVirtualPixelMethod:
2841 if (cache_info->random_info == (RandomInfo *) NULL)
2842 cache_info->random_info=AcquireRandomInfo();
2843 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2844 RandomX(cache_info->random_info,cache_info->columns),
2845 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2846 *virtual_nexus,exception);
2847 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2850 case DitherVirtualPixelMethod:
2852 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2853 DitherX(x_offset,cache_info->columns),
2854 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2856 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2859 case TileVirtualPixelMethod:
2861 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2862 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2863 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2864 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2866 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2869 case MirrorVirtualPixelMethod:
2871 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2872 if ((x_modulo.quotient & 0x01) == 1L)
2873 x_modulo.remainder=(ssize_t) cache_info->columns-
2874 x_modulo.remainder-1L;
2875 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2876 if ((y_modulo.quotient & 0x01) == 1L)
2877 y_modulo.remainder=(ssize_t) cache_info->rows-
2878 y_modulo.remainder-1L;
2879 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2880 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2882 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2885 case HorizontalTileEdgeVirtualPixelMethod:
2887 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2888 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2889 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2890 *virtual_nexus,exception);
2891 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2894 case VerticalTileEdgeVirtualPixelMethod:
2896 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2897 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2898 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2899 *virtual_nexus,exception);
2900 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2903 case BackgroundVirtualPixelMethod:
2904 case BlackVirtualPixelMethod:
2905 case GrayVirtualPixelMethod:
2906 case TransparentVirtualPixelMethod:
2907 case MaskVirtualPixelMethod:
2908 case WhiteVirtualPixelMethod:
2911 r=virtual_metacontent;
2914 case CheckerTileVirtualPixelMethod:
2916 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2917 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2918 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2921 r=virtual_metacontent;
2924 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2925 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2927 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2930 case HorizontalTileVirtualPixelMethod:
2932 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2935 r=virtual_metacontent;
2938 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2939 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2940 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2941 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2943 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2946 case VerticalTileVirtualPixelMethod:
2948 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2951 r=virtual_metacontent;
2954 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2955 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2956 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2957 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2959 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2963 if (p == (const Quantum *) NULL)
2965 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2967 q+=cache_info->number_channels;
2968 if ((s != (void *) NULL) && (r != (const void *) NULL))
2970 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2971 s+=cache_info->metacontent_extent;
2976 Transfer a run of pixels.
2978 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2979 (size_t) length,1UL,*virtual_nexus,exception);
2980 if (p == (const Quantum *) NULL)
2982 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2983 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2984 q+=length*cache_info->number_channels;
2985 if ((r != (void *) NULL) && (s != (const void *) NULL))
2987 (void) memcpy(s,r,(size_t) length);
2988 s+=length*cache_info->metacontent_extent;
2991 if (u < (ssize_t) columns)
2997 if (virtual_metacontent != (void *) NULL)
2998 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
2999 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3000 if (v < (ssize_t) rows)
3001 return((const Quantum *) NULL);
3006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3010 + G e t V i r t u a l P i x e l C a c h e %
3014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3016 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3017 % cache as defined by the geometry parameters. A pointer to the pixels
3018 % is returned if the pixels are transferred, otherwise a NULL is returned.
3020 % The format of the GetVirtualPixelCache() method is:
3022 % const Quantum *GetVirtualPixelCache(const Image *image,
3023 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3024 % const ssize_t y,const size_t columns,const size_t rows,
3025 % ExceptionInfo *exception)
3027 % A description of each parameter follows:
3029 % o image: the image.
3031 % o virtual_pixel_method: the virtual pixel method.
3033 % o x,y,columns,rows: These values define the perimeter of a region of
3036 % o exception: return any errors or warnings in this structure.
3039 static const Quantum *GetVirtualPixelCache(const Image *image,
3040 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3041 const size_t columns,const size_t rows,ExceptionInfo *exception)
3044 *magick_restrict cache_info;
3047 id = GetOpenMPThreadId();
3052 assert(image != (const Image *) NULL);
3053 assert(image->signature == MagickCoreSignature);
3054 assert(image->cache != (Cache) NULL);
3055 cache_info=(CacheInfo *) image->cache;
3056 assert(cache_info->signature == MagickCoreSignature);
3057 assert(id < (int) cache_info->number_threads);
3058 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3059 cache_info->nexus_info[id],exception);
3064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3068 % G e t V i r t u a l P i x e l Q u e u e %
3072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3074 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3075 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3077 % The format of the GetVirtualPixelQueue() method is:
3079 % const Quantum *GetVirtualPixelQueue(const Image image)
3081 % A description of each parameter follows:
3083 % o image: the image.
3086 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3089 *magick_restrict cache_info;
3092 id = GetOpenMPThreadId();
3094 assert(image != (const Image *) NULL);
3095 assert(image->signature == MagickCoreSignature);
3096 assert(image->cache != (Cache) NULL);
3097 cache_info=(CacheInfo *) image->cache;
3098 assert(cache_info->signature == MagickCoreSignature);
3099 if (cache_info->methods.get_virtual_pixels_handler !=
3100 (GetVirtualPixelsHandler) NULL)
3101 return(cache_info->methods.get_virtual_pixels_handler(image));
3102 assert(id < (int) cache_info->number_threads);
3103 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3111 % G e t V i r t u a l P i x e l s %
3115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3117 % GetVirtualPixels() returns an immutable pixel region. If the
3118 % region is successfully accessed, a pointer to it is returned, otherwise
3119 % NULL is returned. The returned pointer may point to a temporary working
3120 % copy of the pixels or it may point to the original pixels in memory.
3121 % Performance is maximized if the selected region is part of one row, or one
3122 % or more full rows, since there is opportunity to access the pixels in-place
3123 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3124 % returned pointer must *never* be deallocated by the user.
3126 % Pixels accessed via the returned pointer represent a simple array of type
3127 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3128 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3129 % access the meta-content (of type void) corresponding to the the
3132 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3134 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3135 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3136 % GetCacheViewAuthenticPixels() instead.
3138 % The format of the GetVirtualPixels() method is:
3140 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3141 % const ssize_t y,const size_t columns,const size_t rows,
3142 % ExceptionInfo *exception)
3144 % A description of each parameter follows:
3146 % o image: the image.
3148 % o x,y,columns,rows: These values define the perimeter of a region of
3151 % o exception: return any errors or warnings in this structure.
3154 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3155 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3156 ExceptionInfo *exception)
3159 *magick_restrict cache_info;
3162 id = GetOpenMPThreadId();
3167 assert(image != (const Image *) NULL);
3168 assert(image->signature == MagickCoreSignature);
3169 assert(image->cache != (Cache) NULL);
3170 cache_info=(CacheInfo *) image->cache;
3171 assert(cache_info->signature == MagickCoreSignature);
3172 if (cache_info->methods.get_virtual_pixel_handler !=
3173 (GetVirtualPixelHandler) NULL)
3174 return(cache_info->methods.get_virtual_pixel_handler(image,
3175 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3176 assert(id < (int) cache_info->number_threads);
3177 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3178 columns,rows,cache_info->nexus_info[id],exception);
3183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3187 + 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 %
3191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3193 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3194 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3196 % The format of the GetVirtualPixelsCache() method is:
3198 % Quantum *GetVirtualPixelsCache(const Image *image)
3200 % A description of each parameter follows:
3202 % o image: the image.
3205 static const Quantum *GetVirtualPixelsCache(const Image *image)
3208 *magick_restrict cache_info;
3211 id = GetOpenMPThreadId();
3213 assert(image != (const Image *) NULL);
3214 assert(image->signature == MagickCoreSignature);
3215 assert(image->cache != (Cache) NULL);
3216 cache_info=(CacheInfo *) image->cache;
3217 assert(cache_info->signature == MagickCoreSignature);
3218 assert(id < (int) cache_info->number_threads);
3219 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3227 + G e t V i r t u a l P i x e l s N e x u s %
3231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3233 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3236 % The format of the GetVirtualPixelsNexus() method is:
3238 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3239 % NexusInfo *nexus_info)
3241 % A description of each parameter follows:
3243 % o cache: the pixel cache.
3245 % o nexus_info: the cache nexus to return the colormap pixels.
3248 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3249 NexusInfo *magick_restrict nexus_info)
3252 *magick_restrict cache_info;
3254 assert(cache != (Cache) NULL);
3255 cache_info=(CacheInfo *) cache;
3256 assert(cache_info->signature == MagickCoreSignature);
3257 if (cache_info->storage_class == UndefinedClass)
3258 return((Quantum *) NULL);
3259 return((const Quantum *) nexus_info->pixels);
3263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3267 + O p e n P i x e l C a c h e %
3271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3273 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3274 % dimensions, allocating space for the image pixels and optionally the
3275 % metacontent, and memory mapping the cache if it is disk based. The cache
3276 % nexus array is initialized as well.
3278 % The format of the OpenPixelCache() method is:
3280 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3281 % ExceptionInfo *exception)
3283 % A description of each parameter follows:
3285 % o image: the image.
3287 % o mode: ReadMode, WriteMode, or IOMode.
3289 % o exception: return any errors or warnings in this structure.
3293 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3300 Open pixel cache on disk.
3302 if ((cache_info->file != -1) && (cache_info->mode == mode))
3303 return(MagickTrue); /* cache already open and in the proper mode */
3304 if (*cache_info->cache_filename == '\0')
3305 file=AcquireUniqueFileResource(cache_info->cache_filename);
3311 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3316 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3317 O_BINARY | O_EXCL,S_MODE);
3319 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3325 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3328 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3333 return(MagickFalse);
3334 (void) AcquireMagickResource(FileResource,1);
3335 if (cache_info->file != -1)
3336 (void) ClosePixelCacheOnDisk(cache_info);
3337 cache_info->file=file;
3341 static inline MagickOffsetType WritePixelCacheRegion(
3342 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3343 const MagickSizeType length,const unsigned char *magick_restrict buffer)
3345 register MagickOffsetType
3351 #if !defined(MAGICKCORE_HAVE_PWRITE)
3352 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3353 return((MagickOffsetType) -1);
3356 for (i=0; i < (MagickOffsetType) length; i+=count)
3358 #if !defined(MAGICKCORE_HAVE_PWRITE)
3359 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3362 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3363 SSIZE_MAX),(off_t) (offset+i));
3375 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3378 *magick_restrict cache_info;
3385 cache_info=(CacheInfo *) image->cache;
3386 if (image->debug != MagickFalse)
3389 format[MagickPathExtent],
3390 message[MagickPathExtent];
3392 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3393 (void) FormatLocaleString(message,MagickPathExtent,
3394 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3395 cache_info->cache_filename,cache_info->file,format);
3396 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3398 if (length != (MagickSizeType) ((MagickOffsetType) length))
3399 return(MagickFalse);
3400 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3402 return(MagickFalse);
3403 if ((MagickSizeType) offset >= length)
3404 count=(MagickOffsetType) 1;
3407 extent=(MagickOffsetType) length-1;
3408 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3411 return(MagickFalse);
3412 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3413 if (cache_info->synchronize != MagickFalse)
3414 (void) posix_fallocate(cache_info->file,offset+1,extent-offset);
3417 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3419 return(MagickFalse);
3423 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3424 ExceptionInfo *exception)
3427 *magick_restrict cache_info,
3431 format[MagickPathExtent],
3432 message[MagickPathExtent];
3449 assert(image != (const Image *) NULL);
3450 assert(image->signature == MagickCoreSignature);
3451 assert(image->cache != (Cache) NULL);
3452 if (image->debug != MagickFalse)
3453 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3454 if (cache_anonymous_memory < 0)
3460 Does the security policy require anonymous mapping for pixel cache?
3462 cache_anonymous_memory=0;
3463 value=GetPolicyValue("pixel-cache-memory");
3464 if (value == (char *) NULL)
3465 value=GetPolicyValue("cache:memory-map");
3466 if (LocaleCompare(value,"anonymous") == 0)
3468 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3469 cache_anonymous_memory=1;
3471 (void) ThrowMagickException(exception,GetMagickModule(),
3472 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3473 "'%s' (policy requires anonymous memory mapping)",image->filename);
3476 value=DestroyString(value);
3478 if ((image->columns == 0) || (image->rows == 0))
3479 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3480 cache_info=(CacheInfo *) image->cache;
3481 assert(cache_info->signature == MagickCoreSignature);
3482 if ((AcquireMagickResource(WidthResource,image->columns) == MagickFalse) ||
3483 (AcquireMagickResource(HeightResource,image->rows) == MagickFalse))
3484 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
3486 source_info=(*cache_info);
3487 source_info.file=(-1);
3488 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3489 image->filename,(double) GetImageIndexInList(image));
3490 cache_info->storage_class=image->storage_class;
3491 cache_info->colorspace=image->colorspace;
3492 cache_info->alpha_trait=image->alpha_trait;
3493 cache_info->read_mask=image->read_mask;
3494 cache_info->write_mask=image->write_mask;
3495 cache_info->rows=image->rows;
3496 cache_info->columns=image->columns;
3497 InitializePixelChannelMap(image);
3498 cache_info->number_channels=GetPixelChannels(image);
3499 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3500 sizeof(*image->channel_map));
3501 cache_info->metacontent_extent=image->metacontent_extent;
3502 cache_info->mode=mode;
3503 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3504 packet_size=cache_info->number_channels*sizeof(Quantum);
3505 if (image->metacontent_extent != 0)
3506 packet_size+=cache_info->metacontent_extent;
3507 length=number_pixels*packet_size;
3508 columns=(size_t) (length/cache_info->rows/packet_size);
3509 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3510 ((ssize_t) cache_info->rows < 0))
3511 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3513 cache_info->length=length;
3514 if (image->ping != MagickFalse)
3516 cache_info->storage_class=image->storage_class;
3517 cache_info->colorspace=image->colorspace;
3518 cache_info->type=PingCache;
3521 status=AcquireMagickResource(AreaResource,cache_info->length);
3522 if (cache_info->mode == PersistMode)
3524 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3525 cache_info->metacontent_extent);
3526 if ((status != MagickFalse) &&
3527 (length == (MagickSizeType) ((size_t) length)) &&
3528 ((cache_info->type == UndefinedCache) || (cache_info->type == MemoryCache)))
3530 status=AcquireMagickResource(MemoryResource,cache_info->length);
3531 if (status != MagickFalse)
3534 if (cache_anonymous_memory <= 0)
3536 cache_info->mapped=MagickFalse;
3537 cache_info->pixels=(Quantum *) MagickAssumeAligned(
3538 AcquireAlignedMemory(1,(size_t) cache_info->length));
3542 cache_info->mapped=MagickTrue;
3543 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3544 cache_info->length);
3546 if (cache_info->pixels == (Quantum *) NULL)
3547 cache_info->pixels=source_info.pixels;
3551 Create memory pixel cache.
3553 cache_info->type=MemoryCache;
3554 cache_info->metacontent=(void *) NULL;
3555 if (cache_info->metacontent_extent != 0)
3556 cache_info->metacontent=(void *) (cache_info->pixels+
3557 number_pixels*cache_info->number_channels);
3558 if ((source_info.storage_class != UndefinedClass) &&
3561 status=ClonePixelCacheRepository(cache_info,&source_info,
3563 RelinquishPixelCachePixels(&source_info);
3565 if (image->debug != MagickFalse)
3567 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3568 MagickPathExtent,format);
3569 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3571 (void) FormatLocaleString(message,MagickPathExtent,
3572 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3573 cache_info->filename,cache_info->mapped != MagickFalse ?
3574 "Anonymous" : "Heap",type,(double) cache_info->columns,
3575 (double) cache_info->rows,(double)
3576 cache_info->number_channels,format);
3577 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3580 return(status == 0 ? MagickFalse : MagickTrue);
3584 status=AcquireMagickResource(DiskResource,cache_info->length);
3585 hosts=(const char *) GetImageRegistry(StringRegistryType,"cache:hosts",
3587 if ((status == MagickFalse) && (hosts != (const char *) NULL))
3593 Distribute the pixel cache to a remote server.
3595 server_info=AcquireDistributeCacheInfo(exception);
3596 if (server_info != (DistributeCacheInfo *) NULL)
3598 status=OpenDistributePixelCache(server_info,image);
3599 if (status == MagickFalse)
3601 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3602 GetDistributeCacheHostname(server_info));
3603 server_info=DestroyDistributeCacheInfo(server_info);
3608 Create a distributed pixel cache.
3611 cache_info->type=DistributedCache;
3612 cache_info->server_info=server_info;
3613 (void) FormatLocaleString(cache_info->cache_filename,
3614 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3615 (DistributeCacheInfo *) cache_info->server_info),
3616 GetDistributeCachePort((DistributeCacheInfo *)
3617 cache_info->server_info));
3618 if ((source_info.storage_class != UndefinedClass) &&
3621 status=ClonePixelCacheRepository(cache_info,&source_info,
3623 RelinquishPixelCachePixels(&source_info);
3625 if (image->debug != MagickFalse)
3627 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3628 MagickPathExtent,format);
3629 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3631 (void) FormatLocaleString(message,MagickPathExtent,
3632 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3633 cache_info->filename,cache_info->cache_filename,
3634 GetDistributeCacheFile((DistributeCacheInfo *)
3635 cache_info->server_info),type,(double) cache_info->columns,
3636 (double) cache_info->rows,(double)
3637 cache_info->number_channels,format);
3638 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3641 return(status == 0 ? MagickFalse : MagickTrue);
3644 cache_info->type=UndefinedCache;
3645 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3646 "CacheResourcesExhausted","`%s'",image->filename);
3647 return(MagickFalse);
3650 Create pixel cache on disk.
3652 if (status == MagickFalse)
3654 cache_info->type=UndefinedCache;
3655 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3656 "CacheResourcesExhausted","`%s'",image->filename);
3657 return(MagickFalse);
3659 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode) &&
3660 (cache_info->mode != PersistMode))
3662 (void) ClosePixelCacheOnDisk(cache_info);
3663 *cache_info->cache_filename='\0';
3665 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3667 RelinquishMagickResource(DiskResource,cache_info->length);
3668 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3670 return(MagickFalse);
3672 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3673 cache_info->length);
3674 if (status == MagickFalse)
3676 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3678 return(MagickFalse);
3680 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3681 cache_info->metacontent_extent);
3682 if (length != (MagickSizeType) ((size_t) length))
3683 cache_info->type=DiskCache;
3686 status=AcquireMagickResource(MapResource,cache_info->length);
3687 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3688 (cache_info->type != MemoryCache))
3691 cache_info->type=DiskCache;
3696 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3697 cache_info->offset,(size_t) cache_info->length);
3698 if (cache_info->pixels == (Quantum *) NULL)
3700 cache_info->type=DiskCache;
3701 cache_info->pixels=source_info.pixels;
3706 Create file-backed memory-mapped pixel cache.
3708 (void) ClosePixelCacheOnDisk(cache_info);
3709 cache_info->type=MapCache;
3710 cache_info->mapped=MagickTrue;
3711 cache_info->metacontent=(void *) NULL;
3712 if (cache_info->metacontent_extent != 0)
3713 cache_info->metacontent=(void *) (cache_info->pixels+
3714 number_pixels*cache_info->number_channels);
3715 if ((source_info.storage_class != UndefinedClass) &&
3718 status=ClonePixelCacheRepository(cache_info,&source_info,
3720 RelinquishPixelCachePixels(&source_info);
3722 if (image->debug != MagickFalse)
3724 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3725 MagickPathExtent,format);
3726 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3728 (void) FormatLocaleString(message,MagickPathExtent,
3729 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3730 cache_info->filename,cache_info->cache_filename,
3731 cache_info->file,type,(double) cache_info->columns,(double)
3732 cache_info->rows,(double) cache_info->number_channels,
3734 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3737 return(status == 0 ? MagickFalse : MagickTrue);
3742 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3744 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3745 RelinquishPixelCachePixels(&source_info);
3747 if (image->debug != MagickFalse)
3749 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3750 MagickPathExtent,format);
3751 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3753 (void) FormatLocaleString(message,MagickPathExtent,
3754 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3755 cache_info->cache_filename,cache_info->file,type,(double)
3756 cache_info->columns,(double) cache_info->rows,(double)
3757 cache_info->number_channels,format);
3758 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3760 return(status == 0 ? MagickFalse : MagickTrue);
3764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3768 + P e r s i s t P i x e l C a c h e %
3772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3774 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3775 % persistent pixel cache is one that resides on disk and is not destroyed
3776 % when the program exits.
3778 % The format of the PersistPixelCache() method is:
3780 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3781 % const MagickBooleanType attach,MagickOffsetType *offset,
3782 % ExceptionInfo *exception)
3784 % A description of each parameter follows:
3786 % o image: the image.
3788 % o filename: the persistent pixel cache filename.
3790 % o attach: A value other than zero initializes the persistent pixel cache.
3792 % o initialize: A value other than zero initializes the persistent pixel
3795 % o offset: the offset in the persistent cache to store pixels.
3797 % o exception: return any errors or warnings in this structure.
3800 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3801 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3802 ExceptionInfo *exception)
3805 *magick_restrict cache_info,
3806 *magick_restrict clone_info;
3814 assert(image != (Image *) NULL);
3815 assert(image->signature == MagickCoreSignature);
3816 if (image->debug != MagickFalse)
3817 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3818 assert(image->cache != (void *) NULL);
3819 assert(filename != (const char *) NULL);
3820 assert(offset != (MagickOffsetType *) NULL);
3821 page_size=GetMagickPageSize();
3822 cache_info=(CacheInfo *) image->cache;
3823 assert(cache_info->signature == MagickCoreSignature);
3824 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3825 CopyOpenCLBuffer(cache_info);
3827 if (attach != MagickFalse)
3830 Attach existing persistent pixel cache.
3832 if (image->debug != MagickFalse)
3833 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3834 "attach persistent cache");
3835 (void) CopyMagickString(cache_info->cache_filename,filename,
3837 cache_info->type=DiskCache;
3838 cache_info->offset=(*offset);
3839 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3840 return(MagickFalse);
3841 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3842 return(SyncImagePixelCache(image,exception));
3845 Clone persistent pixel cache.
3847 status=AcquireMagickResource(DiskResource,cache_info->length);
3848 if (status == MagickFalse)
3850 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3851 "CacheResourcesExhausted","`%s'",image->filename);
3852 return(MagickFalse);
3854 clone_info=(CacheInfo *) ClonePixelCache(cache_info);
3855 clone_info->type=DiskCache;
3856 (void) CopyMagickString(clone_info->cache_filename,filename,MagickPathExtent);
3857 clone_info->file=(-1);
3858 clone_info->storage_class=cache_info->storage_class;
3859 clone_info->colorspace=cache_info->colorspace;
3860 clone_info->alpha_trait=cache_info->alpha_trait;
3861 clone_info->read_mask=cache_info->read_mask;
3862 clone_info->write_mask=cache_info->write_mask;
3863 clone_info->columns=cache_info->columns;
3864 clone_info->rows=cache_info->rows;
3865 clone_info->number_channels=cache_info->number_channels;
3866 clone_info->metacontent_extent=cache_info->metacontent_extent;
3867 clone_info->mode=PersistMode;
3868 clone_info->length=cache_info->length;
3869 (void) memcpy(clone_info->channel_map,cache_info->channel_map,
3870 MaxPixelChannels*sizeof(*cache_info->channel_map));
3871 clone_info->offset=(*offset);
3872 status=ClonePixelCacheRepository(clone_info,cache_info,exception);
3873 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3874 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3883 + 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 %
3887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3889 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3890 % defined by the region rectangle and returns a pointer to the region. This
3891 % region is subsequently transferred from the pixel cache with
3892 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3893 % pixels are transferred, otherwise a NULL is returned.
3895 % The format of the QueueAuthenticPixelCacheNexus() method is:
3897 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3898 % const ssize_t y,const size_t columns,const size_t rows,
3899 % const MagickBooleanType clone,NexusInfo *nexus_info,
3900 % ExceptionInfo *exception)
3902 % A description of each parameter follows:
3904 % o image: the image.
3906 % o x,y,columns,rows: These values define the perimeter of a region of
3909 % o nexus_info: the cache nexus to set.
3911 % o clone: clone the pixel cache.
3913 % o exception: return any errors or warnings in this structure.
3916 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3917 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3918 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3921 *magick_restrict cache_info;
3930 *magick_restrict pixels;
3936 Validate pixel cache geometry.
3938 assert(image != (const Image *) NULL);
3939 assert(image->signature == MagickCoreSignature);
3940 assert(image->cache != (Cache) NULL);
3941 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3942 if (cache_info == (Cache) NULL)
3943 return((Quantum *) NULL);
3944 assert(cache_info->signature == MagickCoreSignature);
3945 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3946 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3947 (y >= (ssize_t) cache_info->rows))
3949 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3950 "PixelsAreNotAuthentic","`%s'",image->filename);
3951 return((Quantum *) NULL);
3953 offset=(MagickOffsetType) y*cache_info->columns+x;
3955 return((Quantum *) NULL);
3956 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3957 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3958 if ((MagickSizeType) offset >= number_pixels)
3959 return((Quantum *) NULL);
3965 region.width=columns;
3967 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3977 + 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 %
3981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3983 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3984 % defined by the region rectangle and returns a pointer to the region. This
3985 % region is subsequently transferred from the pixel cache with
3986 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3987 % pixels are transferred, otherwise a NULL is returned.
3989 % The format of the QueueAuthenticPixelsCache() method is:
3991 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
3992 % const ssize_t y,const size_t columns,const size_t rows,
3993 % ExceptionInfo *exception)
3995 % A description of each parameter follows:
3997 % o image: the image.
3999 % o x,y,columns,rows: These values define the perimeter of a region of
4002 % o exception: return any errors or warnings in this structure.
4005 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4006 const ssize_t y,const size_t columns,const size_t rows,
4007 ExceptionInfo *exception)
4010 *magick_restrict cache_info;
4013 id = GetOpenMPThreadId();
4016 *magick_restrict pixels;
4018 assert(image != (const Image *) NULL);
4019 assert(image->signature == MagickCoreSignature);
4020 assert(image->cache != (Cache) NULL);
4021 cache_info=(CacheInfo *) image->cache;
4022 assert(cache_info->signature == MagickCoreSignature);
4023 assert(id < (int) cache_info->number_threads);
4024 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4025 cache_info->nexus_info[id],exception);
4030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4034 % Q u e u e A u t h e n t i c P i x e l s %
4038 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4040 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4041 % successfully initialized a pointer to a Quantum array representing the
4042 % region is returned, otherwise NULL is returned. The returned pointer may
4043 % point to a temporary working buffer for the pixels or it may point to the
4044 % final location of the pixels in memory.
4046 % Write-only access means that any existing pixel values corresponding to
4047 % the region are ignored. This is useful if the initial image is being
4048 % created from scratch, or if the existing pixel values are to be
4049 % completely replaced without need to refer to their pre-existing values.
4050 % The application is free to read and write the pixel buffer returned by
4051 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4052 % initialize the pixel array values. Initializing pixel array values is the
4053 % application's responsibility.
4055 % Performance is maximized if the selected region is part of one row, or
4056 % one or more full rows, since then there is opportunity to access the
4057 % pixels in-place (without a copy) if the image is in memory, or in a
4058 % memory-mapped file. The returned pointer must *never* be deallocated
4061 % Pixels accessed via the returned pointer represent a simple array of type
4062 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4063 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4064 % obtain the meta-content (of type void) corresponding to the region.
4065 % Once the Quantum (and/or Quantum) array has been updated, the
4066 % changes must be saved back to the underlying image using
4067 % SyncAuthenticPixels() or they may be lost.
4069 % The format of the QueueAuthenticPixels() method is:
4071 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4072 % const ssize_t y,const size_t columns,const size_t rows,
4073 % ExceptionInfo *exception)
4075 % A description of each parameter follows:
4077 % o image: the image.
4079 % o x,y,columns,rows: These values define the perimeter of a region of
4082 % o exception: return any errors or warnings in this structure.
4085 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4086 const ssize_t y,const size_t columns,const size_t rows,
4087 ExceptionInfo *exception)
4090 *magick_restrict cache_info;
4093 id = GetOpenMPThreadId();
4096 *magick_restrict pixels;
4098 assert(image != (Image *) NULL);
4099 assert(image->signature == MagickCoreSignature);
4100 assert(image->cache != (Cache) NULL);
4101 cache_info=(CacheInfo *) image->cache;
4102 assert(cache_info->signature == MagickCoreSignature);
4103 if (cache_info->methods.queue_authentic_pixels_handler !=
4104 (QueueAuthenticPixelsHandler) NULL)
4106 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4107 columns,rows,exception);
4110 assert(id < (int) cache_info->number_threads);
4111 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4112 cache_info->nexus_info[id],exception);
4117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4121 + 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 %
4125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4127 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4130 % The format of the ReadPixelCacheMetacontent() method is:
4132 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4133 % NexusInfo *nexus_info,ExceptionInfo *exception)
4135 % A description of each parameter follows:
4137 % o cache_info: the pixel cache.
4139 % o nexus_info: the cache nexus to read the metacontent.
4141 % o exception: return any errors or warnings in this structure.
4145 static inline MagickOffsetType ReadPixelCacheRegion(
4146 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4147 const MagickSizeType length,unsigned char *magick_restrict buffer)
4149 register MagickOffsetType
4155 #if !defined(MAGICKCORE_HAVE_PREAD)
4156 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4157 return((MagickOffsetType) -1);
4160 for (i=0; i < (MagickOffsetType) length; i+=count)
4162 #if !defined(MAGICKCORE_HAVE_PREAD)
4163 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4166 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4167 SSIZE_MAX),(off_t) (offset+i));
4179 static MagickBooleanType ReadPixelCacheMetacontent(
4180 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4181 ExceptionInfo *exception)
4194 register unsigned char
4200 if (cache_info->metacontent_extent == 0)
4201 return(MagickFalse);
4202 if (nexus_info->authentic_pixel_cache != MagickFalse)
4204 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4205 nexus_info->region.x;
4206 length=(MagickSizeType) nexus_info->region.width*
4207 cache_info->metacontent_extent;
4208 extent=length*nexus_info->region.height;
4209 rows=nexus_info->region.height;
4211 q=(unsigned char *) nexus_info->metacontent;
4212 switch (cache_info->type)
4217 register unsigned char
4221 Read meta-content from memory.
4223 if ((cache_info->columns == nexus_info->region.width) &&
4224 (extent == (MagickSizeType) ((size_t) extent)))
4229 p=(unsigned char *) cache_info->metacontent+offset*
4230 cache_info->metacontent_extent;
4231 for (y=0; y < (ssize_t) rows; y++)
4233 (void) memcpy(q,p,(size_t) length);
4234 p+=cache_info->metacontent_extent*cache_info->columns;
4235 q+=cache_info->metacontent_extent*nexus_info->region.width;
4242 Read meta content from disk.
4244 LockSemaphoreInfo(cache_info->file_semaphore);
4245 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4247 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4248 cache_info->cache_filename);
4249 UnlockSemaphoreInfo(cache_info->file_semaphore);
4250 return(MagickFalse);
4252 if ((cache_info->columns == nexus_info->region.width) &&
4253 (extent <= MagickMaxBufferExtent))
4258 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4259 for (y=0; y < (ssize_t) rows; y++)
4261 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4262 cache_info->number_channels*sizeof(Quantum)+offset*
4263 cache_info->metacontent_extent,length,(unsigned char *) q);
4264 if (count != (MagickOffsetType) length)
4266 offset+=cache_info->columns;
4267 q+=cache_info->metacontent_extent*nexus_info->region.width;
4269 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4270 (void) ClosePixelCacheOnDisk(cache_info);
4271 UnlockSemaphoreInfo(cache_info->file_semaphore);
4274 case DistributedCache:
4280 Read metacontent from distributed cache.
4282 LockSemaphoreInfo(cache_info->file_semaphore);
4283 region=nexus_info->region;
4284 if ((cache_info->columns != nexus_info->region.width) ||
4285 (extent > MagickMaxBufferExtent))
4292 for (y=0; y < (ssize_t) rows; y++)
4294 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4295 cache_info->server_info,®ion,length,(unsigned char *) q);
4296 if (count != (MagickOffsetType) length)
4298 q+=cache_info->metacontent_extent*nexus_info->region.width;
4301 UnlockSemaphoreInfo(cache_info->file_semaphore);
4307 if (y < (ssize_t) rows)
4309 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4310 cache_info->cache_filename);
4311 return(MagickFalse);
4313 if ((cache_info->debug != MagickFalse) &&
4314 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4315 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4316 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4317 nexus_info->region.width,(double) nexus_info->region.height,(double)
4318 nexus_info->region.x,(double) nexus_info->region.y);
4323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4327 + R e a d P i x e l C a c h e P i x e l s %
4331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4333 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4336 % The format of the ReadPixelCachePixels() method is:
4338 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4339 % NexusInfo *nexus_info,ExceptionInfo *exception)
4341 % A description of each parameter follows:
4343 % o cache_info: the pixel cache.
4345 % o nexus_info: the cache nexus to read the pixels.
4347 % o exception: return any errors or warnings in this structure.
4350 static MagickBooleanType ReadPixelCachePixels(
4351 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4352 ExceptionInfo *exception)
4372 if (nexus_info->authentic_pixel_cache != MagickFalse)
4374 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns;
4375 if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4376 return(MagickFalse);
4377 offset+=nexus_info->region.x;
4378 number_channels=cache_info->number_channels;
4379 length=(MagickSizeType) number_channels*nexus_info->region.width*
4381 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4382 return(MagickFalse);
4383 rows=nexus_info->region.height;
4385 if ((extent == 0) || ((extent/length) != rows))
4386 return(MagickFalse);
4388 q=nexus_info->pixels;
4389 switch (cache_info->type)
4398 Read pixels from memory.
4400 if ((cache_info->columns == nexus_info->region.width) &&
4401 (extent == (MagickSizeType) ((size_t) extent)))
4406 p=cache_info->pixels+offset*cache_info->number_channels;
4407 for (y=0; y < (ssize_t) rows; y++)
4409 (void) memcpy(q,p,(size_t) length);
4410 p+=cache_info->number_channels*cache_info->columns;
4411 q+=cache_info->number_channels*nexus_info->region.width;
4418 Read pixels from disk.
4420 LockSemaphoreInfo(cache_info->file_semaphore);
4421 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4423 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4424 cache_info->cache_filename);
4425 UnlockSemaphoreInfo(cache_info->file_semaphore);
4426 return(MagickFalse);
4428 if ((cache_info->columns == nexus_info->region.width) &&
4429 (extent <= MagickMaxBufferExtent))
4434 for (y=0; y < (ssize_t) rows; y++)
4436 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4437 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4438 if (count != (MagickOffsetType) length)
4440 offset+=cache_info->columns;
4441 q+=cache_info->number_channels*nexus_info->region.width;
4443 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4444 (void) ClosePixelCacheOnDisk(cache_info);
4445 UnlockSemaphoreInfo(cache_info->file_semaphore);
4448 case DistributedCache:
4454 Read pixels from distributed cache.
4456 LockSemaphoreInfo(cache_info->file_semaphore);
4457 region=nexus_info->region;
4458 if ((cache_info->columns != nexus_info->region.width) ||
4459 (extent > MagickMaxBufferExtent))
4466 for (y=0; y < (ssize_t) rows; y++)
4468 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4469 cache_info->server_info,®ion,length,(unsigned char *) q);
4470 if (count != (MagickOffsetType) length)
4472 q+=cache_info->number_channels*nexus_info->region.width;
4475 UnlockSemaphoreInfo(cache_info->file_semaphore);
4481 if (y < (ssize_t) rows)
4483 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4484 cache_info->cache_filename);
4485 return(MagickFalse);
4487 if ((cache_info->debug != MagickFalse) &&
4488 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4489 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4490 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4491 nexus_info->region.width,(double) nexus_info->region.height,(double)
4492 nexus_info->region.x,(double) nexus_info->region.y);
4497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4501 + R e f e r e n c e P i x e l C a c h e %
4505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4507 % ReferencePixelCache() increments the reference count associated with the
4508 % pixel cache returning a pointer to the cache.
4510 % The format of the ReferencePixelCache method is:
4512 % Cache ReferencePixelCache(Cache cache_info)
4514 % A description of each parameter follows:
4516 % o cache_info: the pixel cache.
4519 MagickPrivate Cache ReferencePixelCache(Cache cache)
4522 *magick_restrict cache_info;
4524 assert(cache != (Cache *) NULL);
4525 cache_info=(CacheInfo *) cache;
4526 assert(cache_info->signature == MagickCoreSignature);
4527 LockSemaphoreInfo(cache_info->semaphore);
4528 cache_info->reference_count++;
4529 UnlockSemaphoreInfo(cache_info->semaphore);
4534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4538 + R e s e t P i x e l C a c h e C h a n n e l s %
4542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4544 % ResetPixelCacheChannels() resets the pixel cache channels.
4546 % The format of the ResetPixelCacheChannels method is:
4548 % void ResetPixelCacheChannels(Image *)
4550 % A description of each parameter follows:
4552 % o image: the image.
4555 MagickPrivate void ResetPixelCacheChannels(Image *image)
4558 *magick_restrict cache_info;
4560 assert(image != (const Image *) NULL);
4561 assert(image->signature == MagickCoreSignature);
4562 assert(image->cache != (Cache) NULL);
4563 cache_info=(CacheInfo *) image->cache;
4564 assert(cache_info->signature == MagickCoreSignature);
4565 cache_info->number_channels=GetPixelChannels(image);
4569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4573 + R e s e t P i x e l C a c h e E p o c h %
4577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4579 % ResetPixelCacheEpoch() resets the pixel cache epoch.
4581 % The format of the ResetPixelCacheEpoch method is:
4583 % void ResetPixelCacheEpoch(void)
4586 MagickPrivate void ResetPixelCacheEpoch(void)
4592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4596 + S e t P i x e l C a c h e M e t h o d s %
4600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4602 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4604 % The format of the SetPixelCacheMethods() method is:
4606 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4608 % A description of each parameter follows:
4610 % o cache: the pixel cache.
4612 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4615 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4618 *magick_restrict cache_info;
4620 GetOneAuthenticPixelFromHandler
4621 get_one_authentic_pixel_from_handler;
4623 GetOneVirtualPixelFromHandler
4624 get_one_virtual_pixel_from_handler;
4627 Set cache pixel methods.
4629 assert(cache != (Cache) NULL);
4630 assert(cache_methods != (CacheMethods *) NULL);
4631 cache_info=(CacheInfo *) cache;
4632 assert(cache_info->signature == MagickCoreSignature);
4633 if (cache_info->debug != MagickFalse)
4634 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4635 cache_info->filename);
4636 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4637 cache_info->methods.get_virtual_pixel_handler=
4638 cache_methods->get_virtual_pixel_handler;
4639 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4640 cache_info->methods.destroy_pixel_handler=
4641 cache_methods->destroy_pixel_handler;
4642 if (cache_methods->get_virtual_metacontent_from_handler !=
4643 (GetVirtualMetacontentFromHandler) NULL)
4644 cache_info->methods.get_virtual_metacontent_from_handler=
4645 cache_methods->get_virtual_metacontent_from_handler;
4646 if (cache_methods->get_authentic_pixels_handler !=
4647 (GetAuthenticPixelsHandler) NULL)
4648 cache_info->methods.get_authentic_pixels_handler=
4649 cache_methods->get_authentic_pixels_handler;
4650 if (cache_methods->queue_authentic_pixels_handler !=
4651 (QueueAuthenticPixelsHandler) NULL)
4652 cache_info->methods.queue_authentic_pixels_handler=
4653 cache_methods->queue_authentic_pixels_handler;
4654 if (cache_methods->sync_authentic_pixels_handler !=
4655 (SyncAuthenticPixelsHandler) NULL)
4656 cache_info->methods.sync_authentic_pixels_handler=
4657 cache_methods->sync_authentic_pixels_handler;
4658 if (cache_methods->get_authentic_pixels_from_handler !=
4659 (GetAuthenticPixelsFromHandler) NULL)
4660 cache_info->methods.get_authentic_pixels_from_handler=
4661 cache_methods->get_authentic_pixels_from_handler;
4662 if (cache_methods->get_authentic_metacontent_from_handler !=
4663 (GetAuthenticMetacontentFromHandler) NULL)
4664 cache_info->methods.get_authentic_metacontent_from_handler=
4665 cache_methods->get_authentic_metacontent_from_handler;
4666 get_one_virtual_pixel_from_handler=
4667 cache_info->methods.get_one_virtual_pixel_from_handler;
4668 if (get_one_virtual_pixel_from_handler !=
4669 (GetOneVirtualPixelFromHandler) NULL)
4670 cache_info->methods.get_one_virtual_pixel_from_handler=
4671 cache_methods->get_one_virtual_pixel_from_handler;
4672 get_one_authentic_pixel_from_handler=
4673 cache_methods->get_one_authentic_pixel_from_handler;
4674 if (get_one_authentic_pixel_from_handler !=
4675 (GetOneAuthenticPixelFromHandler) NULL)
4676 cache_info->methods.get_one_authentic_pixel_from_handler=
4677 cache_methods->get_one_authentic_pixel_from_handler;
4681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4685 + S e t P i x e l C a c h e N e x u s P i x e l s %
4689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4691 % SetPixelCacheNexusPixels() defines the region of the cache for the
4692 % specified cache nexus.
4694 % The format of the SetPixelCacheNexusPixels() method is:
4696 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4697 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4698 % ExceptionInfo *exception)
4700 % A description of each parameter follows:
4702 % o cache_info: the pixel cache.
4704 % o mode: ReadMode, WriteMode, or IOMode.
4706 % o region: A pointer to the RectangleInfo structure that defines the
4707 % region of this particular cache nexus.
4709 % o nexus_info: the cache nexus to set.
4711 % o exception: return any errors or warnings in this structure.
4715 static inline MagickBooleanType AcquireCacheNexusPixels(
4716 const CacheInfo *magick_restrict cache_info,NexusInfo *nexus_info,
4717 ExceptionInfo *exception)
4719 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4720 return(MagickFalse);
4721 if (cache_anonymous_memory <= 0)
4723 nexus_info->mapped=MagickFalse;
4724 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4725 (size_t) nexus_info->length));
4726 if (nexus_info->cache != (Quantum *) NULL)
4727 (void) ResetMagickMemory(nexus_info->cache,0,(size_t)
4728 nexus_info->length);
4732 nexus_info->mapped=MagickTrue;
4733 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4734 nexus_info->length);
4736 if (nexus_info->cache == (Quantum *) NULL)
4738 (void) ThrowMagickException(exception,GetMagickModule(),
4739 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4740 cache_info->filename);
4741 return(MagickFalse);
4746 static inline MagickBooleanType IsPixelCacheAuthentic(
4747 const CacheInfo *magick_restrict cache_info,
4748 const NexusInfo *magick_restrict nexus_info)
4757 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4759 if (cache_info->type == PingCache)
4761 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4762 nexus_info->region.x;
4763 status=nexus_info->pixels == (cache_info->pixels+offset*
4764 cache_info->number_channels) ? MagickTrue : MagickFalse;
4768 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4771 if (mode == ReadMode)
4773 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4776 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4779 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4780 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4781 ExceptionInfo *exception)
4790 assert(cache_info != (const CacheInfo *) NULL);
4791 assert(cache_info->signature == MagickCoreSignature);
4792 if (cache_info->type == UndefinedCache)
4793 return((Quantum *) NULL);
4794 if ((region->width == 0) || (region->height == 0))
4795 return((Quantum *) NULL);
4796 nexus_info->region=(*region);
4797 number_pixels=(MagickSizeType) nexus_info->region.width*
4798 nexus_info->region.height;
4799 if (number_pixels == 0)
4800 return((Quantum *) NULL);
4801 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4807 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4808 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4809 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4810 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4811 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4812 ((nexus_info->region.width == cache_info->columns) ||
4813 ((nexus_info->region.width % cache_info->columns) == 0)))))
4819 Pixels are accessed directly from memory.
4821 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4822 nexus_info->region.x;
4823 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4825 nexus_info->metacontent=(void *) NULL;
4826 if (cache_info->metacontent_extent != 0)
4827 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4828 offset*cache_info->metacontent_extent;
4829 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4830 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4832 return(nexus_info->pixels);
4836 Pixels are stored in a staging region until they are synced to the cache.
4838 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4839 if (cache_info->metacontent_extent != 0)
4840 length+=number_pixels*cache_info->metacontent_extent;
4841 if (nexus_info->cache == (Quantum *) NULL)
4843 nexus_info->length=length;
4844 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4845 if (status == MagickFalse)
4847 nexus_info->length=0;
4848 return((Quantum *) NULL);
4852 if (nexus_info->length < length)
4854 RelinquishCacheNexusPixels(nexus_info);
4855 nexus_info->length=length;
4856 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4857 if (status == MagickFalse)
4859 nexus_info->length=0;
4860 return((Quantum *) NULL);
4863 nexus_info->pixels=nexus_info->cache;
4864 nexus_info->metacontent=(void *) NULL;
4865 if (cache_info->metacontent_extent != 0)
4866 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4867 cache_info->number_channels);
4868 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4869 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4871 return(nexus_info->pixels);
4875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4879 % 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 %
4883 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4885 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4886 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4887 % access that is outside the boundaries of the image cache.
4889 % The format of the SetPixelCacheVirtualMethod() method is:
4891 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4892 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4894 % A description of each parameter follows:
4896 % o image: the image.
4898 % o virtual_pixel_method: choose the type of virtual pixel.
4900 % o exception: return any errors or warnings in this structure.
4904 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4905 ExceptionInfo *exception)
4908 *magick_restrict cache_info;
4911 *magick_restrict image_view;
4919 assert(image != (Image *) NULL);
4920 assert(image->signature == MagickCoreSignature);
4921 if (image->debug != MagickFalse)
4922 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4923 assert(image->cache != (Cache) NULL);
4924 cache_info=(CacheInfo *) image->cache;
4925 assert(cache_info->signature == MagickCoreSignature);
4926 image->alpha_trait=BlendPixelTrait;
4928 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4929 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4930 #pragma omp parallel for schedule(static,4) shared(status) \
4931 magick_number_threads(image,image,image->rows,1)
4933 for (y=0; y < (ssize_t) image->rows; y++)
4941 if (status == MagickFalse)
4943 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4944 if (q == (Quantum *) NULL)
4949 for (x=0; x < (ssize_t) image->columns; x++)
4951 SetPixelAlpha(image,alpha,q);
4952 q+=GetPixelChannels(image);
4954 status=SyncCacheViewAuthenticPixels(image_view,exception);
4956 image_view=DestroyCacheView(image_view);
4960 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4961 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4964 *magick_restrict cache_info;
4969 assert(image != (Image *) NULL);
4970 assert(image->signature == MagickCoreSignature);
4971 if (image->debug != MagickFalse)
4972 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4973 assert(image->cache != (Cache) NULL);
4974 cache_info=(CacheInfo *) image->cache;
4975 assert(cache_info->signature == MagickCoreSignature);
4976 method=cache_info->virtual_pixel_method;
4977 cache_info->virtual_pixel_method=virtual_pixel_method;
4978 if ((image->columns != 0) && (image->rows != 0))
4979 switch (virtual_pixel_method)
4981 case BackgroundVirtualPixelMethod:
4983 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
4984 (image->alpha_trait == UndefinedPixelTrait))
4985 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4986 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4987 (IsGrayColorspace(image->colorspace) != MagickFalse))
4988 (void) SetImageColorspace(image,sRGBColorspace,exception);
4991 case TransparentVirtualPixelMethod:
4993 if (image->alpha_trait == UndefinedPixelTrait)
4994 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5003 #if defined(MAGICKCORE_OPENCL_SUPPORT)
5005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5009 + 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 %
5013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5015 % SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
5016 % been completed and updates the host memory.
5018 % The format of the SyncAuthenticOpenCLBuffer() method is:
5020 % void SyncAuthenticOpenCLBuffer(const Image *image)
5022 % A description of each parameter follows:
5024 % o image: the image.
5028 static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5030 assert(cache_info != (CacheInfo *) NULL);
5031 assert(cache_info->signature == MagickCoreSignature);
5032 if ((cache_info->type != MemoryCache) ||
5033 (cache_info->opencl == (MagickCLCacheInfo) NULL))
5036 Ensure single threaded access to OpenCL environment.
5038 LockSemaphoreInfo(cache_info->semaphore);
5039 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
5040 UnlockSemaphoreInfo(cache_info->semaphore);
5043 MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5046 *magick_restrict cache_info;
5048 assert(image != (const Image *) NULL);
5049 cache_info=(CacheInfo *) image->cache;
5050 CopyOpenCLBuffer(cache_info);
5055 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5059 + 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 %
5063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5065 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5066 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5067 % is synced, otherwise MagickFalse.
5069 % The format of the SyncAuthenticPixelCacheNexus() method is:
5071 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5072 % NexusInfo *nexus_info,ExceptionInfo *exception)
5074 % A description of each parameter follows:
5076 % o image: the image.
5078 % o nexus_info: the cache nexus to sync.
5080 % o exception: return any errors or warnings in this structure.
5083 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5084 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5087 *magick_restrict cache_info;
5093 Transfer pixels to the cache.
5095 assert(image != (Image *) NULL);
5096 assert(image->signature == MagickCoreSignature);
5097 if (image->cache == (Cache) NULL)
5098 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5099 cache_info=(CacheInfo *) image->cache;
5100 assert(cache_info->signature == MagickCoreSignature);
5101 if (cache_info->type == UndefinedCache)
5102 return(MagickFalse);
5103 if (nexus_info->authentic_pixel_cache != MagickFalse)
5105 image->taint=MagickTrue;
5108 assert(cache_info->signature == MagickCoreSignature);
5109 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5110 if ((cache_info->metacontent_extent != 0) &&
5111 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5112 return(MagickFalse);
5113 if (status != MagickFalse)
5114 image->taint=MagickTrue;
5119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5123 + S y n c A u t h e n t i c P i x e l C a c h e %
5127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5129 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5130 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5131 % otherwise MagickFalse.
5133 % The format of the SyncAuthenticPixelsCache() method is:
5135 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5136 % ExceptionInfo *exception)
5138 % A description of each parameter follows:
5140 % o image: the image.
5142 % o exception: return any errors or warnings in this structure.
5145 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5146 ExceptionInfo *exception)
5149 *magick_restrict cache_info;
5152 id = GetOpenMPThreadId();
5157 assert(image != (Image *) NULL);
5158 assert(image->signature == MagickCoreSignature);
5159 assert(image->cache != (Cache) NULL);
5160 cache_info=(CacheInfo *) image->cache;
5161 assert(cache_info->signature == MagickCoreSignature);
5162 assert(id < (int) cache_info->number_threads);
5163 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5173 % S y n c A u t h e n t i c P i x e l s %
5177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5179 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5180 % The method returns MagickTrue if the pixel region is flushed, otherwise
5183 % The format of the SyncAuthenticPixels() method is:
5185 % MagickBooleanType SyncAuthenticPixels(Image *image,
5186 % ExceptionInfo *exception)
5188 % A description of each parameter follows:
5190 % o image: the image.
5192 % o exception: return any errors or warnings in this structure.
5195 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5196 ExceptionInfo *exception)
5199 *magick_restrict cache_info;
5202 id = GetOpenMPThreadId();
5207 assert(image != (Image *) NULL);
5208 assert(image->signature == MagickCoreSignature);
5209 assert(image->cache != (Cache) NULL);
5210 cache_info=(CacheInfo *) image->cache;
5211 assert(cache_info->signature == MagickCoreSignature);
5212 if (cache_info->methods.sync_authentic_pixels_handler !=
5213 (SyncAuthenticPixelsHandler) NULL)
5215 status=cache_info->methods.sync_authentic_pixels_handler(image,
5219 assert(id < (int) cache_info->number_threads);
5220 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5230 + S y n c I m a g e P i x e l C a c h e %
5234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5236 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5237 % The method returns MagickTrue if the pixel region is flushed, otherwise
5240 % The format of the SyncImagePixelCache() method is:
5242 % MagickBooleanType SyncImagePixelCache(Image *image,
5243 % ExceptionInfo *exception)
5245 % A description of each parameter follows:
5247 % o image: the image.
5249 % o exception: return any errors or warnings in this structure.
5252 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5253 ExceptionInfo *exception)
5256 *magick_restrict cache_info;
5258 assert(image != (Image *) NULL);
5259 assert(exception != (ExceptionInfo *) NULL);
5260 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5261 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5269 + 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 %
5273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5275 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5276 % of the pixel cache.
5278 % The format of the WritePixelCacheMetacontent() method is:
5280 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5281 % NexusInfo *nexus_info,ExceptionInfo *exception)
5283 % A description of each parameter follows:
5285 % o cache_info: the pixel cache.
5287 % o nexus_info: the cache nexus to write the meta-content.
5289 % o exception: return any errors or warnings in this structure.
5292 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5293 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5303 register const unsigned char
5312 if (cache_info->metacontent_extent == 0)
5313 return(MagickFalse);
5314 if (nexus_info->authentic_pixel_cache != MagickFalse)
5316 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5317 nexus_info->region.x;
5318 length=(MagickSizeType) nexus_info->region.width*
5319 cache_info->metacontent_extent;
5320 extent=(MagickSizeType) length*nexus_info->region.height;
5321 rows=nexus_info->region.height;
5323 p=(unsigned char *) nexus_info->metacontent;
5324 switch (cache_info->type)
5329 register unsigned char
5333 Write associated pixels to memory.
5335 if ((cache_info->columns == nexus_info->region.width) &&
5336 (extent == (MagickSizeType) ((size_t) extent)))
5341 q=(unsigned char *) cache_info->metacontent+offset*
5342 cache_info->metacontent_extent;
5343 for (y=0; y < (ssize_t) rows; y++)
5345 (void) memcpy(q,p,(size_t) length);
5346 p+=nexus_info->region.width*cache_info->metacontent_extent;
5347 q+=cache_info->columns*cache_info->metacontent_extent;
5354 Write associated pixels to disk.
5356 LockSemaphoreInfo(cache_info->file_semaphore);
5357 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5359 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5360 cache_info->cache_filename);
5361 UnlockSemaphoreInfo(cache_info->file_semaphore);
5362 return(MagickFalse);
5364 if ((cache_info->columns == nexus_info->region.width) &&
5365 (extent <= MagickMaxBufferExtent))
5370 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5371 for (y=0; y < (ssize_t) rows; y++)
5373 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5374 cache_info->number_channels*sizeof(Quantum)+offset*
5375 cache_info->metacontent_extent,length,(const unsigned char *) p);
5376 if (count != (MagickOffsetType) length)
5378 p+=cache_info->metacontent_extent*nexus_info->region.width;
5379 offset+=cache_info->columns;
5381 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5382 (void) ClosePixelCacheOnDisk(cache_info);
5383 UnlockSemaphoreInfo(cache_info->file_semaphore);
5386 case DistributedCache:
5392 Write metacontent to distributed cache.
5394 LockSemaphoreInfo(cache_info->file_semaphore);
5395 region=nexus_info->region;
5396 if ((cache_info->columns != nexus_info->region.width) ||
5397 (extent > MagickMaxBufferExtent))
5404 for (y=0; y < (ssize_t) rows; y++)
5406 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5407 cache_info->server_info,®ion,length,(const unsigned char *) p);
5408 if (count != (MagickOffsetType) length)
5410 p+=cache_info->metacontent_extent*nexus_info->region.width;
5413 UnlockSemaphoreInfo(cache_info->file_semaphore);
5419 if (y < (ssize_t) rows)
5421 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5422 cache_info->cache_filename);
5423 return(MagickFalse);
5425 if ((cache_info->debug != MagickFalse) &&
5426 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5427 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5428 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5429 nexus_info->region.width,(double) nexus_info->region.height,(double)
5430 nexus_info->region.x,(double) nexus_info->region.y);
5435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5439 + W r i t e C a c h e P i x e l s %
5443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5445 % WritePixelCachePixels() writes image pixels to the specified region of the
5448 % The format of the WritePixelCachePixels() method is:
5450 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5451 % NexusInfo *nexus_info,ExceptionInfo *exception)
5453 % A description of each parameter follows:
5455 % o cache_info: the pixel cache.
5457 % o nexus_info: the cache nexus to write the pixels.
5459 % o exception: return any errors or warnings in this structure.
5462 static MagickBooleanType WritePixelCachePixels(
5463 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5464 ExceptionInfo *exception)
5474 register const Quantum
5483 if (nexus_info->authentic_pixel_cache != MagickFalse)
5485 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5486 nexus_info->region.x;
5487 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5489 extent=length*nexus_info->region.height;
5490 rows=nexus_info->region.height;
5492 p=nexus_info->pixels;
5493 switch (cache_info->type)
5502 Write pixels to memory.
5504 if ((cache_info->columns == nexus_info->region.width) &&
5505 (extent == (MagickSizeType) ((size_t) extent)))
5510 q=cache_info->pixels+offset*cache_info->number_channels;
5511 for (y=0; y < (ssize_t) rows; y++)
5513 (void) memcpy(q,p,(size_t) length);
5514 p+=cache_info->number_channels*nexus_info->region.width;
5515 q+=cache_info->number_channels*cache_info->columns;
5522 Write pixels to disk.
5524 LockSemaphoreInfo(cache_info->file_semaphore);
5525 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5527 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5528 cache_info->cache_filename);
5529 UnlockSemaphoreInfo(cache_info->file_semaphore);
5530 return(MagickFalse);
5532 if ((cache_info->columns == nexus_info->region.width) &&
5533 (extent <= MagickMaxBufferExtent))
5538 for (y=0; y < (ssize_t) rows; y++)
5540 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5541 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5543 if (count != (MagickOffsetType) length)
5545 p+=cache_info->number_channels*nexus_info->region.width;
5546 offset+=cache_info->columns;
5548 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5549 (void) ClosePixelCacheOnDisk(cache_info);
5550 UnlockSemaphoreInfo(cache_info->file_semaphore);
5553 case DistributedCache:
5559 Write pixels to distributed cache.
5561 LockSemaphoreInfo(cache_info->file_semaphore);
5562 region=nexus_info->region;
5563 if ((cache_info->columns != nexus_info->region.width) ||
5564 (extent > MagickMaxBufferExtent))
5571 for (y=0; y < (ssize_t) rows; y++)
5573 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5574 cache_info->server_info,®ion,length,(const unsigned char *) p);
5575 if (count != (MagickOffsetType) length)
5577 p+=cache_info->number_channels*nexus_info->region.width;
5580 UnlockSemaphoreInfo(cache_info->file_semaphore);
5586 if (y < (ssize_t) rows)
5588 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5589 cache_info->cache_filename);
5590 return(MagickFalse);
5592 if ((cache_info->debug != MagickFalse) &&
5593 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5594 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5595 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5596 nexus_info->region.width,(double) nexus_info->region.height,(double)
5597 nexus_info->region.x,(double) nexus_info->region.y);