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)
153 static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
157 *cache_semaphore = (SemaphoreInfo *) NULL;
160 cache_anonymous_memory = (-1);
166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 + A c q u i r e P i x e l C a c h e %
174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 % AcquirePixelCache() acquires a pixel cache.
178 % The format of the AcquirePixelCache() method is:
180 % Cache AcquirePixelCache(const size_t number_threads)
182 % A description of each parameter follows:
184 % o number_threads: the number of nexus threads.
187 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
190 *magick_restrict cache_info;
195 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
196 if (cache_info == (CacheInfo *) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
199 cache_info->type=UndefinedCache;
200 cache_info->mode=IOMode;
201 cache_info->colorspace=sRGBColorspace;
202 cache_info->file=(-1);
203 cache_info->id=GetMagickThreadId();
204 cache_info->number_threads=number_threads;
205 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
206 cache_info->number_threads=GetOpenMPMaximumThreads();
207 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
208 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
209 if (cache_info->number_threads == 0)
210 cache_info->number_threads=1;
211 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
212 if (cache_info->nexus_info == (NexusInfo **) NULL)
213 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
214 value=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
215 if (value != (const char *) NULL)
217 cache_info->synchronize=IsStringTrue(value);
218 value=DestroyString(value);
220 value=GetPolicyValue("cache:synchronize");
221 if (value != (const char *) NULL)
223 cache_info->synchronize=IsStringTrue(value);
224 value=DestroyString(value);
226 cache_info->semaphore=AcquireSemaphoreInfo();
227 cache_info->reference_count=1;
228 cache_info->file_semaphore=AcquireSemaphoreInfo();
229 cache_info->debug=IsEventLogging();
230 cache_info->signature=MagickCoreSignature;
231 return((Cache ) cache_info);
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % A c q u i r e P i x e l C a c h e N e x u s %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
247 % The format of the AcquirePixelCacheNexus method is:
249 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
251 % A description of each parameter follows:
253 % o number_threads: the number of nexus threads.
256 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
259 **magick_restrict nexus_info;
264 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
265 number_threads,sizeof(*nexus_info)));
266 if (nexus_info == (NexusInfo **) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
269 sizeof(**nexus_info));
270 if (nexus_info[0] == (NexusInfo *) NULL)
271 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
272 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
273 for (i=0; i < (ssize_t) number_threads; i++)
275 nexus_info[i]=(&nexus_info[0][i]);
276 nexus_info[i]->signature=MagickCoreSignature;
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
286 + A c q u i r e P i x e l C a c h e P i x e l s %
290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 % AcquirePixelCachePixels() returns the pixels associated with the specified
295 % The format of the AcquirePixelCachePixels() method is:
297 % const void *AcquirePixelCachePixels(const Image *image,
298 % MagickSizeType *length,ExceptionInfo *exception)
300 % A description of each parameter follows:
302 % o image: the image.
304 % o length: the pixel cache length.
306 % o exception: return any errors or warnings in this structure.
309 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
310 MagickSizeType *length,ExceptionInfo *exception)
313 *magick_restrict cache_info;
315 assert(image != (const Image *) NULL);
316 assert(image->signature == MagickCoreSignature);
317 assert(exception != (ExceptionInfo *) NULL);
318 assert(exception->signature == MagickCoreSignature);
319 assert(image->cache != (Cache) NULL);
320 cache_info=(CacheInfo *) image->cache;
321 assert(cache_info->signature == MagickCoreSignature);
323 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
324 return((const void *) NULL);
325 *length=cache_info->length;
326 return((const void *) cache_info->pixels);
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334 + C a c h e C o m p o n e n t G e n e s i s %
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 % CacheComponentGenesis() instantiates the cache component.
342 % The format of the CacheComponentGenesis method is:
344 % MagickBooleanType CacheComponentGenesis(void)
347 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
349 if (cache_semaphore == (SemaphoreInfo *) NULL)
350 cache_semaphore=AcquireSemaphoreInfo();
355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
359 + C a c h e C o m p o n e n t T e r m i n u s %
363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 % CacheComponentTerminus() destroys the cache component.
367 % The format of the CacheComponentTerminus() method is:
369 % CacheComponentTerminus(void)
372 MagickPrivate void CacheComponentTerminus(void)
374 if (cache_semaphore == (SemaphoreInfo *) NULL)
375 ActivateSemaphoreInfo(&cache_semaphore);
376 LockSemaphoreInfo(cache_semaphore);
377 instantiate_cache=MagickFalse;
378 UnlockSemaphoreInfo(cache_semaphore);
379 RelinquishSemaphoreInfo(&cache_semaphore);
383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
387 + C l o n e P i x e l C a c h e %
391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
393 % ClonePixelCache() clones a pixel cache.
395 % The format of the ClonePixelCache() method is:
397 % Cache ClonePixelCache(const Cache cache)
399 % A description of each parameter follows:
401 % o cache: the pixel cache.
404 MagickPrivate Cache ClonePixelCache(const Cache cache)
407 *magick_restrict clone_info;
410 *magick_restrict cache_info;
412 assert(cache != NULL);
413 cache_info=(const CacheInfo *) cache;
414 assert(cache_info->signature == MagickCoreSignature);
415 if (cache_info->debug != MagickFalse)
416 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
417 cache_info->filename);
418 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
419 if (clone_info == (Cache) NULL)
420 return((Cache) NULL);
421 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
422 return((Cache ) clone_info);
426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430 + C l o n e P i x e l C a c h e M e t h o d s %
434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
439 % The format of the ClonePixelCacheMethods() method is:
441 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
443 % A description of each parameter follows:
445 % o clone: Specifies a pointer to a Cache structure.
447 % o cache: the pixel cache.
450 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
453 *magick_restrict cache_info,
454 *magick_restrict source_info;
456 assert(clone != (Cache) NULL);
457 source_info=(CacheInfo *) clone;
458 assert(source_info->signature == MagickCoreSignature);
459 if (source_info->debug != MagickFalse)
460 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
461 source_info->filename);
462 assert(cache != (Cache) NULL);
463 cache_info=(CacheInfo *) cache;
464 assert(cache_info->signature == MagickCoreSignature);
465 source_info->methods=cache_info->methods;
469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473 + 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 %
477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
479 % ClonePixelCacheRepository() clones the source pixel cache to the destination
482 % The format of the ClonePixelCacheRepository() method is:
484 % MagickBooleanType ClonePixelCacheRepository(CacheInfo *cache_info,
485 % CacheInfo *source_info,ExceptionInfo *exception)
487 % A description of each parameter follows:
489 % o cache_info: the pixel cache.
491 % o source_info: the source pixel cache.
493 % o exception: return any errors or warnings in this structure.
497 static MagickBooleanType ClonePixelCacheOnDisk(
498 CacheInfo *magick_restrict cache_info,CacheInfo *magick_restrict clone_info)
516 Clone pixel cache on disk with identical morphology.
518 if ((OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) ||
519 (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse))
521 quantum=(size_t) MagickMaxBufferExtent;
522 if ((fstat(cache_info->file,&file_stats) == 0) && (file_stats.st_size > 0))
523 quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
524 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer));
525 if (buffer == (unsigned char *) NULL)
526 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
528 while ((count=read(cache_info->file,buffer,quantum)) > 0)
533 number_bytes=write(clone_info->file,buffer,(size_t) count);
534 if (number_bytes != count)
536 extent+=number_bytes;
538 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
539 if (extent != cache_info->length)
544 static MagickBooleanType ClonePixelCacheRepository(
545 CacheInfo *magick_restrict clone_info,CacheInfo *magick_restrict cache_info,
546 ExceptionInfo *exception)
548 #define MaxCacheThreads 2
549 #define cache_threads(source,destination) \
550 num_threads(((source)->type == DiskCache) || \
551 ((destination)->type == DiskCache) || (((source)->rows) < \
552 (16*GetMagickResourceLimit(ThreadResource))) ? 1 : \
553 GetMagickResourceLimit(ThreadResource) < MaxCacheThreads ? \
554 GetMagickResourceLimit(ThreadResource) : MaxCacheThreads)
561 **magick_restrict cache_nexus,
562 **magick_restrict clone_nexus;
570 assert(cache_info != (CacheInfo *) NULL);
571 assert(clone_info != (CacheInfo *) NULL);
572 assert(exception != (ExceptionInfo *) NULL);
573 if (cache_info->type == PingCache)
575 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
576 if ((cache_info->columns == clone_info->columns) &&
577 (cache_info->rows == clone_info->rows) &&
578 (cache_info->number_channels == clone_info->number_channels) &&
579 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) &&
580 (cache_info->metacontent_extent == clone_info->metacontent_extent))
583 Identical pixel cache morphology.
585 if (((cache_info->type == MemoryCache) ||
586 (cache_info->type == MapCache)) &&
587 ((clone_info->type == MemoryCache) ||
588 (clone_info->type == MapCache)))
590 (void) memcpy(clone_info->pixels,cache_info->pixels,
591 cache_info->columns*cache_info->number_channels*cache_info->rows*
592 sizeof(*cache_info->pixels));
593 if ((cache_info->metacontent_extent != 0) &&
594 (clone_info->metacontent_extent != 0))
595 (void) memcpy(clone_info->metacontent,cache_info->metacontent,
596 cache_info->columns*cache_info->rows*
597 clone_info->metacontent_extent*sizeof(unsigned char));
600 if ((cache_info->type == DiskCache) && (clone_info->type == DiskCache))
601 return(ClonePixelCacheOnDisk(cache_info,clone_info));
604 Mismatched pixel cache morphology.
606 cache_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
607 clone_nexus=AcquirePixelCacheNexus(MaxCacheThreads);
608 if ((cache_nexus == (NexusInfo **) NULL) ||
609 (clone_nexus == (NexusInfo **) NULL))
610 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
611 length=cache_info->number_channels*sizeof(*cache_info->channel_map);
612 optimize=(cache_info->number_channels == clone_info->number_channels) &&
613 (memcmp(cache_info->channel_map,clone_info->channel_map,length) == 0) ?
614 MagickTrue : MagickFalse;
615 length=(size_t) MagickMin(cache_info->columns*cache_info->number_channels,
616 clone_info->columns*clone_info->number_channels);
618 #if defined(MAGICKCORE_OPENMP_SUPPORT)
619 #pragma omp parallel for schedule(static,4) shared(status) \
620 cache_threads(cache_info,clone_info)
622 for (y=0; y < (ssize_t) cache_info->rows; y++)
625 id = GetOpenMPThreadId();
636 if (status == MagickFalse)
638 if (y >= (ssize_t) clone_info->rows)
640 region.width=cache_info->columns;
644 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
645 cache_nexus[id],exception);
646 if (pixels == (Quantum *) NULL)
648 status=ReadPixelCachePixels(cache_info,cache_nexus[id],exception);
649 if (status == MagickFalse)
651 region.width=clone_info->columns;
652 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
653 clone_nexus[id],exception);
654 if (pixels == (Quantum *) NULL)
656 (void) ResetMagickMemory(clone_nexus[id]->pixels,0,(size_t)
657 clone_nexus[id]->length);
658 if (optimize != MagickFalse)
659 (void) memcpy(clone_nexus[id]->pixels,cache_nexus[id]->pixels,length*
663 register const Quantum
670 Mismatched pixel channel map.
672 p=cache_nexus[id]->pixels;
673 q=clone_nexus[id]->pixels;
674 for (x=0; x < (ssize_t) cache_info->columns; x++)
679 if (x == (ssize_t) clone_info->columns)
681 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
689 channel=clone_info->channel_map[i].channel;
690 traits=cache_info->channel_map[channel].traits;
691 if (traits != UndefinedPixelTrait)
692 *q=*(p+cache_info->channel_map[channel].offset);
695 p+=cache_info->number_channels;
698 status=WritePixelCachePixels(clone_info,clone_nexus[id],exception);
700 if ((cache_info->metacontent_extent != 0) &&
701 (clone_info->metacontent_extent != 0))
706 length=(size_t) MagickMin(cache_info->metacontent_extent,
707 clone_info->metacontent_extent);
708 #if defined(MAGICKCORE_OPENMP_SUPPORT)
709 #pragma omp parallel for schedule(static,4) shared(status) \
710 cache_threads(cache_info,clone_info)
712 for (y=0; y < (ssize_t) cache_info->rows; y++)
715 id = GetOpenMPThreadId();
723 if (status == MagickFalse)
725 if (y >= (ssize_t) clone_info->rows)
727 region.width=cache_info->columns;
731 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,
732 cache_nexus[id],exception);
733 if (pixels == (Quantum *) NULL)
735 status=ReadPixelCacheMetacontent(cache_info,cache_nexus[id],exception);
736 if (status == MagickFalse)
738 region.width=clone_info->columns;
739 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,®ion,
740 clone_nexus[id],exception);
741 if (pixels == (Quantum *) NULL)
743 if ((clone_nexus[id]->metacontent != (void *) NULL) &&
744 (cache_nexus[id]->metacontent != (void *) NULL))
745 (void) memcpy(clone_nexus[id]->metacontent,
746 cache_nexus[id]->metacontent,length*sizeof(unsigned char));
747 status=WritePixelCacheMetacontent(clone_info,clone_nexus[id],exception);
750 cache_nexus=DestroyPixelCacheNexus(cache_nexus,MaxCacheThreads);
751 clone_nexus=DestroyPixelCacheNexus(clone_nexus,MaxCacheThreads);
752 if (cache_info->debug != MagickFalse)
755 message[MagickPathExtent];
757 (void) FormatLocaleString(message,MagickPathExtent,"%s => %s",
758 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
759 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
760 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
770 + D e s t r o y I m a g e P i x e l C a c h e %
774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
776 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
778 % The format of the DestroyImagePixelCache() method is:
780 % void DestroyImagePixelCache(Image *image)
782 % A description of each parameter follows:
784 % o image: the image.
787 static void DestroyImagePixelCache(Image *image)
789 assert(image != (Image *) NULL);
790 assert(image->signature == MagickCoreSignature);
791 if (image->debug != MagickFalse)
792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
793 if (image->cache == (void *) NULL)
795 image->cache=DestroyPixelCache(image->cache);
799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
803 + D e s t r o y I m a g e P i x e l s %
807 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
809 % DestroyImagePixels() deallocates memory associated with the pixel cache.
811 % The format of the DestroyImagePixels() method is:
813 % void DestroyImagePixels(Image *image)
815 % A description of each parameter follows:
817 % o image: the image.
820 MagickExport void DestroyImagePixels(Image *image)
823 *magick_restrict cache_info;
825 assert(image != (const Image *) NULL);
826 assert(image->signature == MagickCoreSignature);
827 if (image->debug != MagickFalse)
828 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
829 assert(image->cache != (Cache) NULL);
830 cache_info=(CacheInfo *) image->cache;
831 assert(cache_info->signature == MagickCoreSignature);
832 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
834 cache_info->methods.destroy_pixel_handler(image);
837 image->cache=DestroyPixelCache(image->cache);
841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
845 + D e s t r o y P i x e l C a c h e %
849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
851 % DestroyPixelCache() deallocates memory associated with the pixel cache.
853 % The format of the DestroyPixelCache() method is:
855 % Cache DestroyPixelCache(Cache cache)
857 % A description of each parameter follows:
859 % o cache: the pixel cache.
863 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
869 if (cache_info->file != -1)
871 status=close(cache_info->file);
872 cache_info->file=(-1);
873 RelinquishMagickResource(FileResource,1);
875 return(status == -1 ? MagickFalse : MagickTrue);
878 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
880 switch (cache_info->type)
884 #if defined(MAGICKCORE_OPENCL_SUPPORT)
885 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
887 cache_info->opencl=RelinquishMagickCLCacheInfo(cache_info->opencl,
889 cache_info->pixels=(Quantum *) NULL;
893 if (cache_info->mapped == MagickFalse)
894 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
897 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
898 RelinquishMagickResource(MemoryResource,cache_info->length);
903 (void) UnmapBlob(cache_info->pixels,(size_t) cache_info->length);
904 cache_info->pixels=(Quantum *) NULL;
905 if ((cache_info->mode != ReadMode) && (cache_info->mode != PersistMode))
906 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
907 *cache_info->cache_filename='\0';
908 RelinquishMagickResource(MapResource,cache_info->length);
912 if (cache_info->file != -1)
913 (void) ClosePixelCacheOnDisk(cache_info);
914 if ((cache_info->mode != ReadMode) && (cache_info->mode != PersistMode))
915 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
916 *cache_info->cache_filename='\0';
917 RelinquishMagickResource(DiskResource,cache_info->length);
920 case DistributedCache:
922 *cache_info->cache_filename='\0';
923 (void) RelinquishDistributePixelCache((DistributeCacheInfo *)
924 cache_info->server_info);
930 cache_info->type=UndefinedCache;
931 cache_info->mapped=MagickFalse;
932 cache_info->metacontent=(void *) NULL;
935 MagickPrivate Cache DestroyPixelCache(Cache cache)
938 *magick_restrict cache_info;
940 assert(cache != (Cache) NULL);
941 cache_info=(CacheInfo *) cache;
942 assert(cache_info->signature == MagickCoreSignature);
943 if (cache_info->debug != MagickFalse)
944 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
945 cache_info->filename);
946 LockSemaphoreInfo(cache_info->semaphore);
947 cache_info->reference_count--;
948 if (cache_info->reference_count != 0)
950 UnlockSemaphoreInfo(cache_info->semaphore);
951 return((Cache) NULL);
953 UnlockSemaphoreInfo(cache_info->semaphore);
954 if (cache_info->debug != MagickFalse)
957 message[MagickPathExtent];
959 (void) FormatLocaleString(message,MagickPathExtent,"destroy %s",
960 cache_info->filename);
961 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
963 RelinquishPixelCachePixels(cache_info);
964 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
965 cache_info->server_info=DestroyDistributeCacheInfo((DistributeCacheInfo *)
966 cache_info->server_info);
967 if (cache_info->nexus_info != (NexusInfo **) NULL)
968 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
969 cache_info->number_threads);
970 if (cache_info->random_info != (RandomInfo *) NULL)
971 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
972 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
973 RelinquishSemaphoreInfo(&cache_info->file_semaphore);
974 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
975 RelinquishSemaphoreInfo(&cache_info->semaphore);
976 cache_info->signature=(~MagickCoreSignature);
977 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
987 + D e s t r o y P i x e l C a c h e N e x u s %
991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
993 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
995 % The format of the DestroyPixelCacheNexus() method is:
997 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
998 % const size_t number_threads)
1000 % A description of each parameter follows:
1002 % o nexus_info: the nexus to destroy.
1004 % o number_threads: the number of nexus threads.
1008 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1010 if (nexus_info->mapped == MagickFalse)
1011 (void) RelinquishAlignedMemory(nexus_info->cache);
1013 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1014 nexus_info->cache=(Quantum *) NULL;
1015 nexus_info->pixels=(Quantum *) NULL;
1016 nexus_info->metacontent=(void *) NULL;
1017 nexus_info->length=0;
1018 nexus_info->mapped=MagickFalse;
1021 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1022 const size_t number_threads)
1027 assert(nexus_info != (NexusInfo **) NULL);
1028 for (i=0; i < (ssize_t) number_threads; i++)
1030 if (nexus_info[i]->cache != (Quantum *) NULL)
1031 RelinquishCacheNexusPixels(nexus_info[i]);
1032 nexus_info[i]->signature=(~MagickCoreSignature);
1034 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1035 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1044 % G e t A u t h e n t i c M e t a c o n t e n t %
1048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1050 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1051 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1052 % returned if the associated pixels are not available.
1054 % The format of the GetAuthenticMetacontent() method is:
1056 % void *GetAuthenticMetacontent(const Image *image)
1058 % A description of each parameter follows:
1060 % o image: the image.
1063 MagickExport void *GetAuthenticMetacontent(const Image *image)
1066 *magick_restrict cache_info;
1069 id = GetOpenMPThreadId();
1071 assert(image != (const Image *) NULL);
1072 assert(image->signature == MagickCoreSignature);
1073 assert(image->cache != (Cache) NULL);
1074 cache_info=(CacheInfo *) image->cache;
1075 assert(cache_info->signature == MagickCoreSignature);
1076 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1077 (GetAuthenticMetacontentFromHandler) NULL)
1082 metacontent=cache_info->methods.
1083 get_authentic_metacontent_from_handler(image);
1084 return(metacontent);
1086 assert(id < (int) cache_info->number_threads);
1087 return(cache_info->nexus_info[id]->metacontent);
1091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1095 + 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 %
1099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1101 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1102 % with the last call to QueueAuthenticPixelsCache() or
1103 % GetAuthenticPixelsCache().
1105 % The format of the GetAuthenticMetacontentFromCache() method is:
1107 % void *GetAuthenticMetacontentFromCache(const Image *image)
1109 % A description of each parameter follows:
1111 % o image: the image.
1114 static void *GetAuthenticMetacontentFromCache(const Image *image)
1117 *magick_restrict cache_info;
1120 id = GetOpenMPThreadId();
1122 assert(image != (const Image *) NULL);
1123 assert(image->signature == MagickCoreSignature);
1124 assert(image->cache != (Cache) NULL);
1125 cache_info=(CacheInfo *) image->cache;
1126 assert(cache_info->signature == MagickCoreSignature);
1127 assert(id < (int) cache_info->number_threads);
1128 return(cache_info->nexus_info[id]->metacontent);
1131 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1137 + G e t A u t h e n t i c O p e n C L B u f f e r %
1141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1143 % GetAuthenticOpenCLBuffer() returns an OpenCL buffer used to execute OpenCL
1146 % The format of the GetAuthenticOpenCLBuffer() method is:
1148 % cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1149 % MagickCLDevice device,ExceptionInfo *exception)
1151 % A description of each parameter follows:
1153 % o image: the image.
1155 % o device: the device to use.
1157 % o exception: return any errors or warnings in this structure.
1160 MagickPrivate cl_mem GetAuthenticOpenCLBuffer(const Image *image,
1161 MagickCLDevice device,ExceptionInfo *exception)
1164 *magick_restrict cache_info;
1169 assert(image != (const Image *) NULL);
1170 assert(device != (const MagickCLDevice) NULL);
1171 cache_info=(CacheInfo *) image->cache;
1172 if (cache_info->type == UndefinedCache)
1173 SyncImagePixelCache((Image *) image,exception);
1174 if ((cache_info->type != MemoryCache) || (cache_info->mapped != MagickFalse))
1175 return((cl_mem) NULL);
1176 if ((cache_info->opencl != (MagickCLCacheInfo) NULL) &&
1177 (cache_info->opencl->device->context != device->context))
1178 cache_info->opencl=CopyMagickCLCacheInfo(cache_info->opencl);
1179 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1181 assert(cache_info->pixels != (Quantum *) NULL);
1182 cache_info->opencl=AcquireMagickCLCacheInfo(device,cache_info->pixels,
1183 cache_info->length);
1184 if (cache_info->opencl == (MagickCLCacheInfo) NULL)
1185 return((cl_mem) NULL);
1187 assert(cache_info->opencl->pixels == cache_info->pixels);
1188 return(cache_info->opencl->buffer);
1193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1197 + 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 %
1201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1203 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1204 % disk pixel cache as defined by the geometry parameters. A pointer to the
1205 % pixels is returned if the pixels are transferred, otherwise a NULL is
1208 % The format of the GetAuthenticPixelCacheNexus() method is:
1210 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1211 % const ssize_t y,const size_t columns,const size_t rows,
1212 % NexusInfo *nexus_info,ExceptionInfo *exception)
1214 % A description of each parameter follows:
1216 % o image: the image.
1218 % o x,y,columns,rows: These values define the perimeter of a region of
1221 % o nexus_info: the cache nexus to return.
1223 % o exception: return any errors or warnings in this structure.
1227 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1228 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
1229 ExceptionInfo *exception)
1232 *magick_restrict cache_info;
1235 *magick_restrict pixels;
1238 Transfer pixels from the cache.
1240 assert(image != (Image *) NULL);
1241 assert(image->signature == MagickCoreSignature);
1242 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1243 nexus_info,exception);
1244 if (pixels == (Quantum *) NULL)
1245 return((Quantum *) NULL);
1246 cache_info=(CacheInfo *) image->cache;
1247 assert(cache_info->signature == MagickCoreSignature);
1248 if (nexus_info->authentic_pixel_cache != MagickFalse)
1250 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1251 return((Quantum *) NULL);
1252 if (cache_info->metacontent_extent != 0)
1253 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1254 return((Quantum *) NULL);
1259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1263 + 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 %
1267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1269 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1270 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1272 % The format of the GetAuthenticPixelsFromCache() method is:
1274 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1276 % A description of each parameter follows:
1278 % o image: the image.
1281 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1284 *magick_restrict cache_info;
1287 id = GetOpenMPThreadId();
1289 assert(image != (const Image *) NULL);
1290 assert(image->signature == MagickCoreSignature);
1291 assert(image->cache != (Cache) NULL);
1292 cache_info=(CacheInfo *) image->cache;
1293 assert(cache_info->signature == MagickCoreSignature);
1294 assert(id < (int) cache_info->number_threads);
1295 return(cache_info->nexus_info[id]->pixels);
1299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 % G e t A u t h e n t i c P i x e l Q u e u e %
1307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309 % GetAuthenticPixelQueue() returns the authentic pixels associated
1310 % corresponding with the last call to QueueAuthenticPixels() or
1311 % GetAuthenticPixels().
1313 % The format of the GetAuthenticPixelQueue() method is:
1315 % Quantum *GetAuthenticPixelQueue(const Image image)
1317 % A description of each parameter follows:
1319 % o image: the image.
1322 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1325 *magick_restrict cache_info;
1328 id = GetOpenMPThreadId();
1330 assert(image != (const Image *) NULL);
1331 assert(image->signature == MagickCoreSignature);
1332 assert(image->cache != (Cache) NULL);
1333 cache_info=(CacheInfo *) image->cache;
1334 assert(cache_info->signature == MagickCoreSignature);
1335 if (cache_info->methods.get_authentic_pixels_from_handler !=
1336 (GetAuthenticPixelsFromHandler) NULL)
1337 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1338 assert(id < (int) cache_info->number_threads);
1339 return(cache_info->nexus_info[id]->pixels);
1343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1347 % G e t A u t h e n t i c P i x e l s %
1351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1354 % region is successfully accessed, a pointer to a Quantum array
1355 % representing the region is returned, otherwise NULL is returned.
1357 % The returned pointer may point to a temporary working copy of the pixels
1358 % or it may point to the original pixels in memory. Performance is maximized
1359 % if the selected region is part of one row, or one or more full rows, since
1360 % then there is opportunity to access the pixels in-place (without a copy)
1361 % if the image is in memory, or in a memory-mapped file. The returned pointer
1362 % must *never* be deallocated by the user.
1364 % Pixels accessed via the returned pointer represent a simple array of type
1365 % Quantum. If the image has corresponding metacontent,call
1366 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1367 % meta-content corresponding to the region. Once the Quantum array has
1368 % been updated, the changes must be saved back to the underlying image using
1369 % SyncAuthenticPixels() or they may be lost.
1371 % The format of the GetAuthenticPixels() method is:
1373 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1374 % const ssize_t y,const size_t columns,const size_t rows,
1375 % ExceptionInfo *exception)
1377 % A description of each parameter follows:
1379 % o image: the image.
1381 % o x,y,columns,rows: These values define the perimeter of a region of
1384 % o exception: return any errors or warnings in this structure.
1387 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1388 const ssize_t y,const size_t columns,const size_t rows,
1389 ExceptionInfo *exception)
1392 *magick_restrict cache_info;
1395 id = GetOpenMPThreadId();
1400 assert(image != (Image *) NULL);
1401 assert(image->signature == MagickCoreSignature);
1402 assert(image->cache != (Cache) NULL);
1403 cache_info=(CacheInfo *) image->cache;
1404 assert(cache_info->signature == MagickCoreSignature);
1405 if (cache_info->methods.get_authentic_pixels_handler !=
1406 (GetAuthenticPixelsHandler) NULL)
1408 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1412 assert(id < (int) cache_info->number_threads);
1413 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1414 cache_info->nexus_info[id],exception);
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423 + G e t A u t h e n t i c P i x e l s C a c h e %
1427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1430 % as defined by the geometry parameters. A pointer to the pixels is returned
1431 % if the pixels are transferred, otherwise a NULL is returned.
1433 % The format of the GetAuthenticPixelsCache() method is:
1435 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1436 % const ssize_t y,const size_t columns,const size_t rows,
1437 % ExceptionInfo *exception)
1439 % A description of each parameter follows:
1441 % o image: the image.
1443 % o x,y,columns,rows: These values define the perimeter of a region of
1446 % o exception: return any errors or warnings in this structure.
1449 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1450 const ssize_t y,const size_t columns,const size_t rows,
1451 ExceptionInfo *exception)
1454 *magick_restrict cache_info;
1457 id = GetOpenMPThreadId();
1460 *magick_restrict pixels;
1462 assert(image != (const Image *) NULL);
1463 assert(image->signature == MagickCoreSignature);
1464 assert(image->cache != (Cache) NULL);
1465 cache_info=(CacheInfo *) image->cache;
1466 if (cache_info == (Cache) NULL)
1467 return((Quantum *) NULL);
1468 assert(cache_info->signature == MagickCoreSignature);
1469 assert(id < (int) cache_info->number_threads);
1470 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1471 cache_info->nexus_info[id],exception);
1476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480 + G e t I m a g e E x t e n t %
1484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1486 % GetImageExtent() returns the extent of the pixels associated corresponding
1487 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1489 % The format of the GetImageExtent() method is:
1491 % MagickSizeType GetImageExtent(const Image *image)
1493 % A description of each parameter follows:
1495 % o image: the image.
1498 MagickExport MagickSizeType GetImageExtent(const Image *image)
1501 *magick_restrict cache_info;
1504 id = GetOpenMPThreadId();
1506 assert(image != (Image *) NULL);
1507 assert(image->signature == MagickCoreSignature);
1508 if (image->debug != MagickFalse)
1509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1510 assert(image->cache != (Cache) NULL);
1511 cache_info=(CacheInfo *) image->cache;
1512 assert(cache_info->signature == MagickCoreSignature);
1513 assert(id < (int) cache_info->number_threads);
1514 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522 + G e t I m a g e P i x e l C a c h e %
1526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1528 % GetImagePixelCache() ensures that there is only a single reference to the
1529 % pixel cache to be modified, updating the provided cache pointer to point to
1530 % a clone of the original pixel cache if necessary.
1532 % The format of the GetImagePixelCache method is:
1534 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1535 % ExceptionInfo *exception)
1537 % A description of each parameter follows:
1539 % o image: the image.
1541 % o clone: any value other than MagickFalse clones the cache pixels.
1543 % o exception: return any errors or warnings in this structure.
1547 static inline MagickBooleanType ValidatePixelCacheMorphology(
1548 const Image *magick_restrict image)
1551 *magick_restrict cache_info;
1553 const PixelChannelMap
1558 Does the image match the pixel cache morphology?
1560 cache_info=(CacheInfo *) image->cache;
1561 p=image->channel_map;
1562 q=cache_info->channel_map;
1563 if ((image->storage_class != cache_info->storage_class) ||
1564 (image->colorspace != cache_info->colorspace) ||
1565 (image->alpha_trait != cache_info->alpha_trait) ||
1566 (image->read_mask != cache_info->read_mask) ||
1567 (image->write_mask != cache_info->write_mask) ||
1568 (image->columns != cache_info->columns) ||
1569 (image->rows != cache_info->rows) ||
1570 (image->number_channels != cache_info->number_channels) ||
1571 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1572 (image->metacontent_extent != cache_info->metacontent_extent) ||
1573 (cache_info->nexus_info == (NexusInfo **) NULL))
1574 return(MagickFalse);
1578 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1579 ExceptionInfo *exception)
1582 *magick_restrict cache_info;
1588 static MagickSizeType
1589 cache_timelimit = MagickResourceInfinity,
1590 cpu_throttle = MagickResourceInfinity,
1594 if (cpu_throttle == MagickResourceInfinity)
1595 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1596 if ((cpu_throttle != 0) && ((cycles++ % 32) == 0))
1597 MagickDelay(cpu_throttle);
1598 if (cache_epoch == 0)
1601 Set the expire time in seconds.
1603 cache_timelimit=GetMagickResourceLimit(TimeResource);
1604 cache_epoch=time((time_t *) NULL);
1606 if ((cache_timelimit != MagickResourceInfinity) &&
1607 ((MagickSizeType) (time((time_t *) NULL)-cache_epoch) >= cache_timelimit))
1609 #if defined(ECANCELED)
1612 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1614 LockSemaphoreInfo(image->semaphore);
1615 assert(image->cache != (Cache) NULL);
1616 cache_info=(CacheInfo *) image->cache;
1617 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1618 CopyOpenCLBuffer(cache_info);
1620 destroy=MagickFalse;
1621 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1623 LockSemaphoreInfo(cache_info->semaphore);
1624 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1635 clone_image=(*image);
1636 clone_image.semaphore=AcquireSemaphoreInfo();
1637 clone_image.reference_count=1;
1638 clone_image.cache=ClonePixelCache(cache_info);
1639 clone_info=(CacheInfo *) clone_image.cache;
1640 status=OpenPixelCache(&clone_image,IOMode,exception);
1641 if (status != MagickFalse)
1643 if (clone != MagickFalse)
1644 status=ClonePixelCacheRepository(clone_info,cache_info,
1646 if (status != MagickFalse)
1648 if (cache_info->reference_count == 1)
1649 cache_info->nexus_info=(NexusInfo **) NULL;
1651 image->cache=clone_image.cache;
1654 RelinquishSemaphoreInfo(&clone_image.semaphore);
1656 UnlockSemaphoreInfo(cache_info->semaphore);
1658 if (destroy != MagickFalse)
1659 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1660 if (status != MagickFalse)
1663 Ensure the image matches the pixel cache morphology.
1665 image->type=UndefinedType;
1666 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1668 status=OpenPixelCache(image,IOMode,exception);
1669 cache_info=(CacheInfo *) image->cache;
1670 if (cache_info->type == DiskCache)
1671 (void) ClosePixelCacheOnDisk(cache_info);
1674 UnlockSemaphoreInfo(image->semaphore);
1675 if (status == MagickFalse)
1676 return((Cache) NULL);
1677 return(image->cache);
1681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685 + G e t I m a g e P i x e l C a c h e T y p e %
1689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1691 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1692 % DiskCache, MemoryCache, MapCache, or PingCache.
1694 % The format of the GetImagePixelCacheType() method is:
1696 % CacheType GetImagePixelCacheType(const Image *image)
1698 % A description of each parameter follows:
1700 % o image: the image.
1703 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1706 *magick_restrict cache_info;
1708 assert(image != (Image *) NULL);
1709 assert(image->signature == MagickCoreSignature);
1710 assert(image->cache != (Cache) NULL);
1711 cache_info=(CacheInfo *) image->cache;
1712 assert(cache_info->signature == MagickCoreSignature);
1713 return(cache_info->type);
1717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1721 % G e t O n e A u t h e n t i c P i x e l %
1725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1727 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1728 % location. The image background color is returned if an error occurs.
1730 % The format of the GetOneAuthenticPixel() method is:
1732 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1733 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1735 % A description of each parameter follows:
1737 % o image: the image.
1739 % o x,y: These values define the location of the pixel to return.
1741 % o pixel: return a pixel at the specified (x,y) location.
1743 % o exception: return any errors or warnings in this structure.
1747 static inline MagickBooleanType CopyPixel(const Image *image,
1748 const Quantum *source,Quantum *destination)
1753 if (source == (const Quantum *) NULL)
1755 destination[RedPixelChannel]=ClampToQuantum(image->background_color.red);
1756 destination[GreenPixelChannel]=ClampToQuantum(
1757 image->background_color.green);
1758 destination[BluePixelChannel]=ClampToQuantum(
1759 image->background_color.blue);
1760 destination[BlackPixelChannel]=ClampToQuantum(
1761 image->background_color.black);
1762 destination[AlphaPixelChannel]=ClampToQuantum(
1763 image->background_color.alpha);
1764 return(MagickFalse);
1766 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1768 PixelChannel channel=GetPixelChannelChannel(image,i);
1769 destination[channel]=source[i];
1774 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1775 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1778 *magick_restrict cache_info;
1783 assert(image != (Image *) NULL);
1784 assert(image->signature == MagickCoreSignature);
1785 assert(image->cache != (Cache) NULL);
1786 cache_info=(CacheInfo *) image->cache;
1787 assert(cache_info->signature == MagickCoreSignature);
1788 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1789 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
1790 (GetOneAuthenticPixelFromHandler) NULL)
1791 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
1793 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
1794 return(CopyPixel(image,q,pixel));
1798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802 + 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 %
1806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1808 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
1809 % location. The image background color is returned if an error occurs.
1811 % The format of the GetOneAuthenticPixelFromCache() method is:
1813 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
1814 % const ssize_t x,const ssize_t y,Quantum *pixel,
1815 % ExceptionInfo *exception)
1817 % A description of each parameter follows:
1819 % o image: the image.
1821 % o x,y: These values define the location of the pixel to return.
1823 % o pixel: return a pixel at the specified (x,y) location.
1825 % o exception: return any errors or warnings in this structure.
1828 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
1829 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1832 *magick_restrict cache_info;
1835 id = GetOpenMPThreadId();
1840 assert(image != (const Image *) NULL);
1841 assert(image->signature == MagickCoreSignature);
1842 assert(image->cache != (Cache) NULL);
1843 cache_info=(CacheInfo *) image->cache;
1844 assert(cache_info->signature == MagickCoreSignature);
1845 assert(id < (int) cache_info->number_threads);
1846 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1847 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
1849 return(CopyPixel(image,q,pixel));
1853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1857 % G e t O n e V i r t u a l P i x e l %
1861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1863 % GetOneVirtualPixel() returns a single virtual pixel at the specified
1864 % (x,y) location. The image background color is returned if an error occurs.
1865 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1867 % The format of the GetOneVirtualPixel() method is:
1869 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
1870 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
1872 % A description of each parameter follows:
1874 % o image: the image.
1876 % o x,y: These values define the location of the pixel to return.
1878 % o pixel: return a pixel at the specified (x,y) location.
1880 % o exception: return any errors or warnings in this structure.
1883 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
1884 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1887 *magick_restrict cache_info;
1890 id = GetOpenMPThreadId();
1895 assert(image != (const Image *) NULL);
1896 assert(image->signature == MagickCoreSignature);
1897 assert(image->cache != (Cache) NULL);
1898 cache_info=(CacheInfo *) image->cache;
1899 assert(cache_info->signature == MagickCoreSignature);
1900 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1901 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
1902 (GetOneVirtualPixelFromHandler) NULL)
1903 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
1904 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
1905 assert(id < (int) cache_info->number_threads);
1906 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
1907 1UL,1UL,cache_info->nexus_info[id],exception);
1908 return(CopyPixel(image,p,pixel));
1912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1916 + 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 %
1920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1922 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
1923 % specified (x,y) location. The image background color is returned if an
1926 % The format of the GetOneVirtualPixelFromCache() method is:
1928 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
1929 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
1930 % Quantum *pixel,ExceptionInfo *exception)
1932 % A description of each parameter follows:
1934 % o image: the image.
1936 % o virtual_pixel_method: the virtual pixel method.
1938 % o x,y: These values define the location of the pixel to return.
1940 % o pixel: return a pixel at the specified (x,y) location.
1942 % o exception: return any errors or warnings in this structure.
1945 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
1946 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
1947 Quantum *pixel,ExceptionInfo *exception)
1950 *magick_restrict cache_info;
1953 id = GetOpenMPThreadId();
1958 assert(image != (const Image *) NULL);
1959 assert(image->signature == MagickCoreSignature);
1960 assert(image->cache != (Cache) NULL);
1961 cache_info=(CacheInfo *) image->cache;
1962 assert(cache_info->signature == MagickCoreSignature);
1963 assert(id < (int) cache_info->number_threads);
1964 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
1965 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
1966 cache_info->nexus_info[id],exception);
1967 return(CopyPixel(image,p,pixel));
1971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1975 % G e t O n e V i r t u a l P i x e l I n f o %
1979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1981 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
1982 % location. The image background color is returned if an error occurs. If
1983 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
1985 % The format of the GetOneVirtualPixelInfo() method is:
1987 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
1988 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
1989 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
1991 % A description of each parameter follows:
1993 % o image: the image.
1995 % o virtual_pixel_method: the virtual pixel method.
1997 % o x,y: these values define the location of the pixel to return.
1999 % o pixel: return a pixel at the specified (x,y) location.
2001 % o exception: return any errors or warnings in this structure.
2004 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2005 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2006 PixelInfo *pixel,ExceptionInfo *exception)
2009 *magick_restrict cache_info;
2012 id = GetOpenMPThreadId();
2014 register const Quantum
2017 assert(image != (const Image *) NULL);
2018 assert(image->signature == MagickCoreSignature);
2019 assert(image->cache != (Cache) NULL);
2020 cache_info=(CacheInfo *) image->cache;
2021 assert(cache_info->signature == MagickCoreSignature);
2022 assert(id < (int) cache_info->number_threads);
2023 GetPixelInfo(image,pixel);
2024 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2025 cache_info->nexus_info[id],exception);
2026 if (p == (const Quantum *) NULL)
2027 return(MagickFalse);
2028 GetPixelInfoPixel(image,p,pixel);
2033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2037 + G e t P i x e l C a c h e C o l o r s p a c e %
2041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2043 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2045 % The format of the GetPixelCacheColorspace() method is:
2047 % Colorspace GetPixelCacheColorspace(Cache cache)
2049 % A description of each parameter follows:
2051 % o cache: the pixel cache.
2054 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2057 *magick_restrict cache_info;
2059 assert(cache != (Cache) NULL);
2060 cache_info=(CacheInfo *) cache;
2061 assert(cache_info->signature == MagickCoreSignature);
2062 if (cache_info->debug != MagickFalse)
2063 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2064 cache_info->filename);
2065 return(cache_info->colorspace);
2069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2073 + G e t P i x e l C a c h e F i l e n a m e %
2077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2079 % GetPixelCacheFilename() returns the filename associated with the pixel
2082 % The format of the GetPixelCacheFilename() method is:
2084 % const char *GetPixelCacheFilename(const Image *image)
2086 % A description of each parameter follows:
2088 % o image: the image.
2091 MagickExport const char *GetPixelCacheFilename(const Image *image)
2094 *magick_restrict cache_info;
2096 assert(image != (const Image *) NULL);
2097 assert(image->signature == MagickCoreSignature);
2098 assert(image->cache != (Cache) NULL);
2099 cache_info=(CacheInfo *) image->cache;
2100 assert(cache_info->signature == MagickCoreSignature);
2101 return(cache_info->cache_filename);
2105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2109 + G e t P i x e l C a c h e M e t h o d s %
2113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2115 % GetPixelCacheMethods() initializes the CacheMethods structure.
2117 % The format of the GetPixelCacheMethods() method is:
2119 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2121 % A description of each parameter follows:
2123 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2126 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2128 assert(cache_methods != (CacheMethods *) NULL);
2129 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2130 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2131 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2132 cache_methods->get_virtual_metacontent_from_handler=
2133 GetVirtualMetacontentFromCache;
2134 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2135 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2136 cache_methods->get_authentic_metacontent_from_handler=
2137 GetAuthenticMetacontentFromCache;
2138 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2139 cache_methods->get_one_authentic_pixel_from_handler=
2140 GetOneAuthenticPixelFromCache;
2141 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2142 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2143 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2151 + G e t P i x e l C a c h e N e x u s E x t e n t %
2155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2157 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2158 % corresponding with the last call to SetPixelCacheNexusPixels() or
2159 % GetPixelCacheNexusPixels().
2161 % The format of the GetPixelCacheNexusExtent() method is:
2163 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2164 % NexusInfo *nexus_info)
2166 % A description of each parameter follows:
2168 % o nexus_info: the nexus info.
2171 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2172 NexusInfo *magick_restrict nexus_info)
2175 *magick_restrict cache_info;
2180 assert(cache != NULL);
2181 cache_info=(CacheInfo *) cache;
2182 assert(cache_info->signature == MagickCoreSignature);
2183 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2185 return((MagickSizeType) cache_info->columns*cache_info->rows);
2190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2194 + G e t P i x e l C a c h e P i x e l s %
2198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2200 % GetPixelCachePixels() returns the pixels associated with the specified image.
2202 % The format of the GetPixelCachePixels() method is:
2204 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2205 % ExceptionInfo *exception)
2207 % A description of each parameter follows:
2209 % o image: the image.
2211 % o length: the pixel cache length.
2213 % o exception: return any errors or warnings in this structure.
2216 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2217 ExceptionInfo *exception)
2220 *magick_restrict cache_info;
2222 assert(image != (const Image *) NULL);
2223 assert(image->signature == MagickCoreSignature);
2224 assert(image->cache != (Cache) NULL);
2225 assert(length != (MagickSizeType *) NULL);
2226 assert(exception != (ExceptionInfo *) NULL);
2227 assert(exception->signature == MagickCoreSignature);
2228 cache_info=(CacheInfo *) image->cache;
2229 assert(cache_info->signature == MagickCoreSignature);
2230 *length=cache_info->length;
2231 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2232 return((void *) NULL);
2233 return((void *) cache_info->pixels);
2237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2241 + 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 %
2245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2249 % The format of the GetPixelCacheStorageClass() method is:
2251 % ClassType GetPixelCacheStorageClass(Cache cache)
2253 % A description of each parameter follows:
2255 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2257 % o cache: the pixel cache.
2260 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2263 *magick_restrict cache_info;
2265 assert(cache != (Cache) NULL);
2266 cache_info=(CacheInfo *) cache;
2267 assert(cache_info->signature == MagickCoreSignature);
2268 if (cache_info->debug != MagickFalse)
2269 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2270 cache_info->filename);
2271 return(cache_info->storage_class);
2275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2279 + G e t P i x e l C a c h e T i l e S i z e %
2283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285 % GetPixelCacheTileSize() returns the pixel cache tile size.
2287 % The format of the GetPixelCacheTileSize() method is:
2289 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2292 % A description of each parameter follows:
2294 % o image: the image.
2296 % o width: the optimized cache tile width in pixels.
2298 % o height: the optimized cache tile height in pixels.
2301 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2305 *magick_restrict cache_info;
2307 assert(image != (Image *) NULL);
2308 assert(image->signature == MagickCoreSignature);
2309 if (image->debug != MagickFalse)
2310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2311 cache_info=(CacheInfo *) image->cache;
2312 assert(cache_info->signature == MagickCoreSignature);
2313 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2314 if (GetImagePixelCacheType(image) == DiskCache)
2315 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2324 + 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 %
2328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2330 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2331 % pixel cache. A virtual pixel is any pixel access that is outside the
2332 % boundaries of the image cache.
2334 % The format of the GetPixelCacheVirtualMethod() method is:
2336 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2338 % A description of each parameter follows:
2340 % o image: the image.
2343 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2346 *magick_restrict cache_info;
2348 assert(image != (Image *) NULL);
2349 assert(image->signature == MagickCoreSignature);
2350 assert(image->cache != (Cache) NULL);
2351 cache_info=(CacheInfo *) image->cache;
2352 assert(cache_info->signature == MagickCoreSignature);
2353 return(cache_info->virtual_pixel_method);
2357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2361 + 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 %
2365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2368 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2370 % The format of the GetVirtualMetacontentFromCache() method is:
2372 % void *GetVirtualMetacontentFromCache(const Image *image)
2374 % A description of each parameter follows:
2376 % o image: the image.
2379 static const void *GetVirtualMetacontentFromCache(const Image *image)
2382 *magick_restrict cache_info;
2385 id = GetOpenMPThreadId();
2388 *magick_restrict metacontent;
2390 assert(image != (const Image *) NULL);
2391 assert(image->signature == MagickCoreSignature);
2392 assert(image->cache != (Cache) NULL);
2393 cache_info=(CacheInfo *) image->cache;
2394 assert(cache_info->signature == MagickCoreSignature);
2395 assert(id < (int) cache_info->number_threads);
2396 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2397 cache_info->nexus_info[id]);
2398 return(metacontent);
2402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2406 + 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 %
2410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2412 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2415 % The format of the GetVirtualMetacontentFromNexus() method is:
2417 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2418 % NexusInfo *nexus_info)
2420 % A description of each parameter follows:
2422 % o cache: the pixel cache.
2424 % o nexus_info: the cache nexus to return the meta-content.
2427 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2428 NexusInfo *magick_restrict nexus_info)
2431 *magick_restrict cache_info;
2433 assert(cache != (Cache) NULL);
2434 cache_info=(CacheInfo *) cache;
2435 assert(cache_info->signature == MagickCoreSignature);
2436 if (cache_info->storage_class == UndefinedClass)
2437 return((void *) NULL);
2438 return(nexus_info->metacontent);
2442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2446 % G e t V i r t u a l M e t a c o n t e n t %
2450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2452 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2453 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2454 % returned if the meta-content are not available.
2456 % The format of the GetVirtualMetacontent() method is:
2458 % const void *GetVirtualMetacontent(const Image *image)
2460 % A description of each parameter follows:
2462 % o image: the image.
2465 MagickExport const void *GetVirtualMetacontent(const Image *image)
2468 *magick_restrict cache_info;
2471 id = GetOpenMPThreadId();
2474 *magick_restrict metacontent;
2476 assert(image != (const Image *) NULL);
2477 assert(image->signature == MagickCoreSignature);
2478 assert(image->cache != (Cache) NULL);
2479 cache_info=(CacheInfo *) image->cache;
2480 assert(cache_info->signature == MagickCoreSignature);
2481 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2482 if (metacontent != (void *) NULL)
2483 return(metacontent);
2484 assert(id < (int) cache_info->number_threads);
2485 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2486 cache_info->nexus_info[id]);
2487 return(metacontent);
2491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2495 + 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 %
2499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2502 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2503 % is returned if the pixels are transferred, otherwise a NULL is returned.
2505 % The format of the GetVirtualPixelsFromNexus() method is:
2507 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2508 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2509 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2510 % ExceptionInfo *exception)
2512 % A description of each parameter follows:
2514 % o image: the image.
2516 % o virtual_pixel_method: the virtual pixel method.
2518 % o x,y,columns,rows: These values define the perimeter of a region of
2521 % o nexus_info: the cache nexus to acquire.
2523 % o exception: return any errors or warnings in this structure.
2530 0, 48, 12, 60, 3, 51, 15, 63,
2531 32, 16, 44, 28, 35, 19, 47, 31,
2532 8, 56, 4, 52, 11, 59, 7, 55,
2533 40, 24, 36, 20, 43, 27, 39, 23,
2534 2, 50, 14, 62, 1, 49, 13, 61,
2535 34, 18, 46, 30, 33, 17, 45, 29,
2536 10, 58, 6, 54, 9, 57, 5, 53,
2537 42, 26, 38, 22, 41, 25, 37, 21
2540 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2545 index=x+DitherMatrix[x & 0x07]-32L;
2548 if (index >= (ssize_t) columns)
2549 return((ssize_t) columns-1L);
2553 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2558 index=y+DitherMatrix[y & 0x07]-32L;
2561 if (index >= (ssize_t) rows)
2562 return((ssize_t) rows-1L);
2566 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2570 if (x >= (ssize_t) columns)
2571 return((ssize_t) (columns-1));
2575 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2579 if (y >= (ssize_t) rows)
2580 return((ssize_t) (rows-1));
2584 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2586 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2589 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2591 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2594 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2595 const size_t extent)
2601 Compute the remainder of dividing offset by extent. It returns not only
2602 the quotient (tile the offset falls in) but also the positive remainer
2603 within that tile such that 0 <= remainder < extent. This method is
2604 essentially a ldiv() using a floored modulo division rather than the
2605 normal default truncated modulo division.
2607 modulo.quotient=offset/(ssize_t) extent;
2610 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2614 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2615 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2616 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2617 ExceptionInfo *exception)
2620 *magick_restrict cache_info;
2630 **magick_restrict virtual_nexus;
2633 *magick_restrict pixels,
2634 virtual_pixel[MaxPixelChannels];
2639 register const Quantum
2652 register unsigned char
2659 *magick_restrict virtual_metacontent;
2664 assert(image != (const Image *) NULL);
2665 assert(image->signature == MagickCoreSignature);
2666 assert(image->cache != (Cache) NULL);
2667 cache_info=(CacheInfo *) image->cache;
2668 assert(cache_info->signature == MagickCoreSignature);
2669 if (cache_info->type == UndefinedCache)
2670 return((const Quantum *) NULL);
2671 #if defined(MAGICKCORE_OPENCL_SUPPORT)
2672 CopyOpenCLBuffer(cache_info);
2676 region.width=columns;
2678 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,®ion,nexus_info,
2680 if (pixels == (Quantum *) NULL)
2681 return((const Quantum *) NULL);
2683 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
2684 nexus_info->region.x;
2685 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
2686 nexus_info->region.width-1L;
2687 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
2688 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
2689 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
2690 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
2696 Pixel request is inside cache extents.
2698 if (nexus_info->authentic_pixel_cache != MagickFalse)
2700 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
2701 if (status == MagickFalse)
2702 return((const Quantum *) NULL);
2703 if (cache_info->metacontent_extent != 0)
2705 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
2706 if (status == MagickFalse)
2707 return((const Quantum *) NULL);
2712 Pixel request is outside cache extents.
2714 s=(unsigned char *) nexus_info->metacontent;
2715 virtual_nexus=AcquirePixelCacheNexus(1);
2716 if (virtual_nexus == (NexusInfo **) NULL)
2718 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
2719 "UnableToGetCacheNexus","`%s'",image->filename);
2720 return((const Quantum *) NULL);
2722 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
2723 sizeof(*virtual_pixel));
2724 virtual_metacontent=(void *) NULL;
2725 switch (virtual_pixel_method)
2727 case BackgroundVirtualPixelMethod:
2728 case BlackVirtualPixelMethod:
2729 case GrayVirtualPixelMethod:
2730 case TransparentVirtualPixelMethod:
2731 case MaskVirtualPixelMethod:
2732 case WhiteVirtualPixelMethod:
2733 case EdgeVirtualPixelMethod:
2734 case CheckerTileVirtualPixelMethod:
2735 case HorizontalTileVirtualPixelMethod:
2736 case VerticalTileVirtualPixelMethod:
2738 if (cache_info->metacontent_extent != 0)
2741 Acquire a metacontent buffer.
2743 virtual_metacontent=(void *) AcquireQuantumMemory(1,
2744 cache_info->metacontent_extent);
2745 if (virtual_metacontent == (void *) NULL)
2747 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
2748 (void) ThrowMagickException(exception,GetMagickModule(),
2749 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
2750 return((const Quantum *) NULL);
2752 (void) ResetMagickMemory(virtual_metacontent,0,
2753 cache_info->metacontent_extent);
2755 switch (virtual_pixel_method)
2757 case BlackVirtualPixelMethod:
2759 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2760 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2761 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2764 case GrayVirtualPixelMethod:
2766 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2767 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
2769 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2772 case TransparentVirtualPixelMethod:
2774 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2775 SetPixelChannel(image,(PixelChannel) i,(Quantum) 0,virtual_pixel);
2776 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
2779 case MaskVirtualPixelMethod:
2780 case WhiteVirtualPixelMethod:
2782 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
2783 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
2784 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
2789 SetPixelRed(image,ClampToQuantum(image->background_color.red),
2791 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
2793 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
2795 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
2797 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
2807 for (v=0; v < (ssize_t) rows; v++)
2813 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
2814 (virtual_pixel_method == UndefinedVirtualPixelMethod))
2815 y_offset=EdgeY(y_offset,cache_info->rows);
2816 for (u=0; u < (ssize_t) columns; u+=length)
2822 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
2823 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
2824 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
2832 Transfer a single pixel.
2834 length=(MagickSizeType) 1;
2835 switch (virtual_pixel_method)
2837 case EdgeVirtualPixelMethod:
2840 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2841 EdgeX(x_offset,cache_info->columns),
2842 EdgeY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2844 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2847 case RandomVirtualPixelMethod:
2849 if (cache_info->random_info == (RandomInfo *) NULL)
2850 cache_info->random_info=AcquireRandomInfo();
2851 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2852 RandomX(cache_info->random_info,cache_info->columns),
2853 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
2854 *virtual_nexus,exception);
2855 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2858 case DitherVirtualPixelMethod:
2860 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2861 DitherX(x_offset,cache_info->columns),
2862 DitherY(y_offset,cache_info->rows),1UL,1UL,*virtual_nexus,
2864 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2867 case TileVirtualPixelMethod:
2869 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2870 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2871 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2872 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2874 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2877 case MirrorVirtualPixelMethod:
2879 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2880 if ((x_modulo.quotient & 0x01) == 1L)
2881 x_modulo.remainder=(ssize_t) cache_info->columns-
2882 x_modulo.remainder-1L;
2883 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2884 if ((y_modulo.quotient & 0x01) == 1L)
2885 y_modulo.remainder=(ssize_t) cache_info->rows-
2886 y_modulo.remainder-1L;
2887 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2888 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2890 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2893 case HorizontalTileEdgeVirtualPixelMethod:
2895 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2896 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2897 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
2898 *virtual_nexus,exception);
2899 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2902 case VerticalTileEdgeVirtualPixelMethod:
2904 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2905 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2906 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
2907 *virtual_nexus,exception);
2908 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2911 case BackgroundVirtualPixelMethod:
2912 case BlackVirtualPixelMethod:
2913 case GrayVirtualPixelMethod:
2914 case TransparentVirtualPixelMethod:
2915 case MaskVirtualPixelMethod:
2916 case WhiteVirtualPixelMethod:
2919 r=virtual_metacontent;
2922 case CheckerTileVirtualPixelMethod:
2924 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2925 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2926 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
2929 r=virtual_metacontent;
2932 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2933 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2935 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2938 case HorizontalTileVirtualPixelMethod:
2940 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
2943 r=virtual_metacontent;
2946 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2947 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2948 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2949 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2951 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2954 case VerticalTileVirtualPixelMethod:
2956 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
2959 r=virtual_metacontent;
2962 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
2963 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
2964 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
2965 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
2967 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2971 if (p == (const Quantum *) NULL)
2973 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
2975 q+=cache_info->number_channels;
2976 if ((s != (void *) NULL) && (r != (const void *) NULL))
2978 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
2979 s+=cache_info->metacontent_extent;
2984 Transfer a run of pixels.
2986 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x_offset,y_offset,
2987 (size_t) length,1UL,*virtual_nexus,exception);
2988 if (p == (const Quantum *) NULL)
2990 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
2991 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
2992 q+=length*cache_info->number_channels;
2993 if ((r != (void *) NULL) && (s != (const void *) NULL))
2995 (void) memcpy(s,r,(size_t) length);
2996 s+=length*cache_info->metacontent_extent;
2999 if (u < (ssize_t) columns)
3005 if (virtual_metacontent != (void *) NULL)
3006 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3007 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3008 if (v < (ssize_t) rows)
3009 return((const Quantum *) NULL);
3014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3018 + G e t V i r t u a l P i x e l C a c h e %
3022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3024 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3025 % cache as defined by the geometry parameters. A pointer to the pixels
3026 % is returned if the pixels are transferred, otherwise a NULL is returned.
3028 % The format of the GetVirtualPixelCache() method is:
3030 % const Quantum *GetVirtualPixelCache(const Image *image,
3031 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3032 % const ssize_t y,const size_t columns,const size_t rows,
3033 % ExceptionInfo *exception)
3035 % A description of each parameter follows:
3037 % o image: the image.
3039 % o virtual_pixel_method: the virtual pixel method.
3041 % o x,y,columns,rows: These values define the perimeter of a region of
3044 % o exception: return any errors or warnings in this structure.
3047 static const Quantum *GetVirtualPixelCache(const Image *image,
3048 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3049 const size_t columns,const size_t rows,ExceptionInfo *exception)
3052 *magick_restrict cache_info;
3055 id = GetOpenMPThreadId();
3060 assert(image != (const Image *) NULL);
3061 assert(image->signature == MagickCoreSignature);
3062 assert(image->cache != (Cache) NULL);
3063 cache_info=(CacheInfo *) image->cache;
3064 assert(cache_info->signature == MagickCoreSignature);
3065 assert(id < (int) cache_info->number_threads);
3066 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3067 cache_info->nexus_info[id],exception);
3072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3076 % G e t V i r t u a l P i x e l Q u e u e %
3080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3082 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3083 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3085 % The format of the GetVirtualPixelQueue() method is:
3087 % const Quantum *GetVirtualPixelQueue(const Image image)
3089 % A description of each parameter follows:
3091 % o image: the image.
3094 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3097 *magick_restrict cache_info;
3100 id = GetOpenMPThreadId();
3102 assert(image != (const Image *) NULL);
3103 assert(image->signature == MagickCoreSignature);
3104 assert(image->cache != (Cache) NULL);
3105 cache_info=(CacheInfo *) image->cache;
3106 assert(cache_info->signature == MagickCoreSignature);
3107 if (cache_info->methods.get_virtual_pixels_handler !=
3108 (GetVirtualPixelsHandler) NULL)
3109 return(cache_info->methods.get_virtual_pixels_handler(image));
3110 assert(id < (int) cache_info->number_threads);
3111 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3119 % G e t V i r t u a l P i x e l s %
3123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3125 % GetVirtualPixels() returns an immutable pixel region. If the
3126 % region is successfully accessed, a pointer to it is returned, otherwise
3127 % NULL is returned. The returned pointer may point to a temporary working
3128 % copy of the pixels or it may point to the original pixels in memory.
3129 % Performance is maximized if the selected region is part of one row, or one
3130 % or more full rows, since there is opportunity to access the pixels in-place
3131 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3132 % returned pointer must *never* be deallocated by the user.
3134 % Pixels accessed via the returned pointer represent a simple array of type
3135 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3136 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3137 % access the meta-content (of type void) corresponding to the the
3140 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3142 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3143 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3144 % GetCacheViewAuthenticPixels() instead.
3146 % The format of the GetVirtualPixels() method is:
3148 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3149 % const ssize_t y,const size_t columns,const size_t rows,
3150 % ExceptionInfo *exception)
3152 % A description of each parameter follows:
3154 % o image: the image.
3156 % o x,y,columns,rows: These values define the perimeter of a region of
3159 % o exception: return any errors or warnings in this structure.
3162 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3163 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3164 ExceptionInfo *exception)
3167 *magick_restrict cache_info;
3170 id = GetOpenMPThreadId();
3175 assert(image != (const Image *) NULL);
3176 assert(image->signature == MagickCoreSignature);
3177 assert(image->cache != (Cache) NULL);
3178 cache_info=(CacheInfo *) image->cache;
3179 assert(cache_info->signature == MagickCoreSignature);
3180 if (cache_info->methods.get_virtual_pixel_handler !=
3181 (GetVirtualPixelHandler) NULL)
3182 return(cache_info->methods.get_virtual_pixel_handler(image,
3183 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3184 assert(id < (int) cache_info->number_threads);
3185 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3186 columns,rows,cache_info->nexus_info[id],exception);
3191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3195 + 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 %
3199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3201 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3202 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3204 % The format of the GetVirtualPixelsCache() method is:
3206 % Quantum *GetVirtualPixelsCache(const Image *image)
3208 % A description of each parameter follows:
3210 % o image: the image.
3213 static const Quantum *GetVirtualPixelsCache(const Image *image)
3216 *magick_restrict cache_info;
3219 id = GetOpenMPThreadId();
3221 assert(image != (const Image *) NULL);
3222 assert(image->signature == MagickCoreSignature);
3223 assert(image->cache != (Cache) NULL);
3224 cache_info=(CacheInfo *) image->cache;
3225 assert(cache_info->signature == MagickCoreSignature);
3226 assert(id < (int) cache_info->number_threads);
3227 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3235 + G e t V i r t u a l P i x e l s N e x u s %
3239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3241 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3244 % The format of the GetVirtualPixelsNexus() method is:
3246 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3247 % NexusInfo *nexus_info)
3249 % A description of each parameter follows:
3251 % o cache: the pixel cache.
3253 % o nexus_info: the cache nexus to return the colormap pixels.
3256 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3257 NexusInfo *magick_restrict nexus_info)
3260 *magick_restrict cache_info;
3262 assert(cache != (Cache) NULL);
3263 cache_info=(CacheInfo *) cache;
3264 assert(cache_info->signature == MagickCoreSignature);
3265 if (cache_info->storage_class == UndefinedClass)
3266 return((Quantum *) NULL);
3267 return((const Quantum *) nexus_info->pixels);
3271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3275 + O p e n P i x e l C a c h e %
3279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3281 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3282 % dimensions, allocating space for the image pixels and optionally the
3283 % metacontent, and memory mapping the cache if it is disk based. The cache
3284 % nexus array is initialized as well.
3286 % The format of the OpenPixelCache() method is:
3288 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3289 % ExceptionInfo *exception)
3291 % A description of each parameter follows:
3293 % o image: the image.
3295 % o mode: ReadMode, WriteMode, or IOMode.
3297 % o exception: return any errors or warnings in this structure.
3301 #if defined(__cplusplus) || defined(c_plusplus)
3306 static void CacheSignalHandler(int status)
3308 ThrowFatalException(CacheFatalError,"UnableToExtendPixelCache");
3312 #if defined(__cplusplus) || defined(c_plusplus)
3316 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
3323 Open pixel cache on disk.
3325 if ((cache_info->file != -1) && (cache_info->mode == mode))
3326 return(MagickTrue); /* cache already open and in the proper mode */
3327 if (*cache_info->cache_filename == '\0')
3328 file=AcquireUniqueFileResource(cache_info->cache_filename);
3334 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3339 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3340 O_BINARY | O_EXCL,S_MODE);
3342 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3348 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3351 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3356 return(MagickFalse);
3357 (void) AcquireMagickResource(FileResource,1);
3358 if (cache_info->file != -1)
3359 (void) ClosePixelCacheOnDisk(cache_info);
3360 cache_info->file=file;
3364 static inline MagickOffsetType WritePixelCacheRegion(
3365 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
3366 const MagickSizeType length,const unsigned char *magick_restrict buffer)
3368 register MagickOffsetType
3374 #if !defined(MAGICKCORE_HAVE_PWRITE)
3375 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3376 return((MagickOffsetType) -1);
3379 for (i=0; i < (MagickOffsetType) length; i+=count)
3381 #if !defined(MAGICKCORE_HAVE_PWRITE)
3382 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3385 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
3386 SSIZE_MAX),(off_t) (offset+i));
3398 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3401 *magick_restrict cache_info;
3408 cache_info=(CacheInfo *) image->cache;
3409 if (image->debug != MagickFalse)
3412 format[MagickPathExtent],
3413 message[MagickPathExtent];
3415 (void) FormatMagickSize(length,MagickFalse,"B",MagickPathExtent,format);
3416 (void) FormatLocaleString(message,MagickPathExtent,
3417 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3418 cache_info->cache_filename,cache_info->file,format);
3419 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3421 if (length != (MagickSizeType) ((MagickOffsetType) length))
3422 return(MagickFalse);
3423 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3425 return(MagickFalse);
3426 if ((MagickSizeType) offset >= length)
3427 count=(MagickOffsetType) 1;
3430 extent=(MagickOffsetType) length-1;
3431 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *)
3434 return(MagickFalse);
3435 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3436 if (cache_info->synchronize != MagickFalse)
3437 (void) posix_fallocate(cache_info->file,offset+1,extent-offset);
3440 (void) signal(SIGBUS,CacheSignalHandler);
3443 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3445 return(MagickFalse);
3449 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3450 ExceptionInfo *exception)
3453 *magick_restrict cache_info,
3457 format[MagickPathExtent],
3458 message[MagickPathExtent];
3474 assert(image != (const Image *) NULL);
3475 assert(image->signature == MagickCoreSignature);
3476 assert(image->cache != (Cache) NULL);
3477 if (image->debug != MagickFalse)
3478 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3479 if (cache_anonymous_memory < 0)
3485 Does the security policy require anonymous mapping for pixel cache?
3487 cache_anonymous_memory=0;
3488 value=GetPolicyValue("pixel-cache-memory");
3489 if (value == (char *) NULL)
3490 value=GetPolicyValue("cache:memory-map");
3491 if (LocaleCompare(value,"anonymous") == 0)
3493 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3494 cache_anonymous_memory=1;
3496 (void) ThrowMagickException(exception,GetMagickModule(),
3497 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn",
3498 "'%s' (policy requires anonymous memory mapping)",image->filename);
3501 value=DestroyString(value);
3503 if ((image->columns == 0) || (image->rows == 0))
3504 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3505 cache_info=(CacheInfo *) image->cache;
3506 assert(cache_info->signature == MagickCoreSignature);
3507 if ((AcquireMagickResource(WidthResource,image->columns) == MagickFalse) ||
3508 (AcquireMagickResource(HeightResource,image->rows) == MagickFalse))
3509 ThrowBinaryException(ImageError,"WidthOrHeightExceedsLimit",
3511 source_info=(*cache_info);
3512 source_info.file=(-1);
3513 (void) FormatLocaleString(cache_info->filename,MagickPathExtent,"%s[%.20g]",
3514 image->filename,(double) GetImageIndexInList(image));
3515 cache_info->storage_class=image->storage_class;
3516 cache_info->colorspace=image->colorspace;
3517 cache_info->alpha_trait=image->alpha_trait;
3518 cache_info->read_mask=image->read_mask;
3519 cache_info->write_mask=image->write_mask;
3520 cache_info->rows=image->rows;
3521 cache_info->columns=image->columns;
3522 InitializePixelChannelMap(image);
3523 cache_info->number_channels=GetPixelChannels(image);
3524 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3525 sizeof(*image->channel_map));
3526 cache_info->metacontent_extent=image->metacontent_extent;
3527 cache_info->mode=mode;
3528 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3529 packet_size=cache_info->number_channels*sizeof(Quantum);
3530 if (image->metacontent_extent != 0)
3531 packet_size+=cache_info->metacontent_extent;
3532 length=number_pixels*packet_size;
3533 columns=(size_t) (length/cache_info->rows/packet_size);
3534 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3535 ((ssize_t) cache_info->rows < 0))
3536 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3538 cache_info->length=length;
3539 if (image->ping != MagickFalse)
3541 cache_info->storage_class=image->storage_class;
3542 cache_info->colorspace=image->colorspace;
3543 cache_info->type=PingCache;
3546 status=AcquireMagickResource(AreaResource,cache_info->length);
3547 if (cache_info->mode == PersistMode)
3549 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3550 cache_info->metacontent_extent);
3551 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3553 status=AcquireMagickResource(MemoryResource,cache_info->length);
3554 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3555 (cache_info->type == MemoryCache))
3558 if (cache_anonymous_memory <= 0)
3560 cache_info->mapped=MagickFalse;
3561 cache_info->pixels=(Quantum *) MagickAssumeAligned(
3562 AcquireAlignedMemory(1,(size_t) cache_info->length));
3566 cache_info->mapped=MagickTrue;
3567 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3568 cache_info->length);
3570 if (cache_info->pixels == (Quantum *) NULL)
3571 cache_info->pixels=source_info.pixels;
3575 Create memory pixel cache.
3577 cache_info->type=MemoryCache;
3578 cache_info->metacontent=(void *) NULL;
3579 if (cache_info->metacontent_extent != 0)
3580 cache_info->metacontent=(void *) (cache_info->pixels+
3581 number_pixels*cache_info->number_channels);
3582 if ((source_info.storage_class != UndefinedClass) &&
3585 status=ClonePixelCacheRepository(cache_info,&source_info,
3587 RelinquishPixelCachePixels(&source_info);
3589 if (image->debug != MagickFalse)
3591 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3592 MagickPathExtent,format);
3593 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3595 (void) FormatLocaleString(message,MagickPathExtent,
3596 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3597 cache_info->filename,cache_info->mapped != MagickFalse ?
3598 "Anonymous" : "Heap",type,(double) cache_info->columns,
3599 (double) cache_info->rows,(double)
3600 cache_info->number_channels,format);
3601 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3604 return(status == 0 ? MagickFalse : MagickTrue);
3607 RelinquishMagickResource(MemoryResource,cache_info->length);
3610 Create pixel cache on disk.
3612 status=AcquireMagickResource(DiskResource,cache_info->length);
3613 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3618 if (cache_info->type == DistributedCache)
3619 RelinquishMagickResource(DiskResource,cache_info->length);
3620 server_info=AcquireDistributeCacheInfo(exception);
3621 if (server_info != (DistributeCacheInfo *) NULL)
3623 status=OpenDistributePixelCache(server_info,image);
3624 if (status == MagickFalse)
3626 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3627 GetDistributeCacheHostname(server_info));
3628 server_info=DestroyDistributeCacheInfo(server_info);
3633 Create a distributed pixel cache.
3636 cache_info->type=DistributedCache;
3637 cache_info->server_info=server_info;
3638 (void) FormatLocaleString(cache_info->cache_filename,
3639 MagickPathExtent,"%s:%d",GetDistributeCacheHostname(
3640 (DistributeCacheInfo *) cache_info->server_info),
3641 GetDistributeCachePort((DistributeCacheInfo *)
3642 cache_info->server_info));
3643 if ((source_info.storage_class != UndefinedClass) &&
3646 status=ClonePixelCacheRepository(cache_info,&source_info,
3648 RelinquishPixelCachePixels(&source_info);
3650 if (image->debug != MagickFalse)
3652 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3653 MagickPathExtent,format);
3654 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3656 (void) FormatLocaleString(message,MagickPathExtent,
3657 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3658 cache_info->filename,cache_info->cache_filename,
3659 GetDistributeCacheFile((DistributeCacheInfo *)
3660 cache_info->server_info),type,(double) cache_info->columns,
3661 (double) cache_info->rows,(double)
3662 cache_info->number_channels,format);
3663 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3666 return(status == 0 ? MagickFalse : MagickTrue);
3669 RelinquishMagickResource(DiskResource,cache_info->length);
3670 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3671 "CacheResourcesExhausted","`%s'",image->filename);
3672 return(MagickFalse);
3674 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode) &&
3675 (cache_info->mode != PersistMode))
3677 (void) ClosePixelCacheOnDisk(cache_info);
3678 *cache_info->cache_filename='\0';
3680 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3682 RelinquishMagickResource(DiskResource,cache_info->length);
3683 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3685 return(MagickFalse);
3687 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3688 cache_info->length);
3689 if (status == MagickFalse)
3691 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3693 return(MagickFalse);
3695 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3696 cache_info->metacontent_extent);
3697 if (length != (MagickSizeType) ((size_t) length))
3698 cache_info->type=DiskCache;
3701 status=AcquireMagickResource(MapResource,cache_info->length);
3702 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3703 (cache_info->type != MemoryCache))
3706 cache_info->type=DiskCache;
3711 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3712 cache_info->offset,(size_t) cache_info->length);
3713 if (cache_info->pixels == (Quantum *) NULL)
3715 cache_info->type=DiskCache;
3716 cache_info->pixels=source_info.pixels;
3721 Create file-backed memory-mapped pixel cache.
3723 (void) ClosePixelCacheOnDisk(cache_info);
3724 cache_info->type=MapCache;
3725 cache_info->mapped=MagickTrue;
3726 cache_info->metacontent=(void *) NULL;
3727 if (cache_info->metacontent_extent != 0)
3728 cache_info->metacontent=(void *) (cache_info->pixels+
3729 number_pixels*cache_info->number_channels);
3730 if ((source_info.storage_class != UndefinedClass) &&
3733 status=ClonePixelCacheRepository(cache_info,&source_info,
3735 RelinquishPixelCachePixels(&source_info);
3737 if (image->debug != MagickFalse)
3739 (void) FormatMagickSize(cache_info->length,MagickTrue,"B",
3740 MagickPathExtent,format);
3741 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3743 (void) FormatLocaleString(message,MagickPathExtent,
3744 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3745 cache_info->filename,cache_info->cache_filename,
3746 cache_info->file,type,(double) cache_info->columns,(double)
3747 cache_info->rows,(double) cache_info->number_channels,
3749 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3752 return(status == 0 ? MagickFalse : MagickTrue);
3755 RelinquishMagickResource(MapResource,cache_info->length);
3758 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3760 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
3761 RelinquishPixelCachePixels(&source_info);
3763 if (image->debug != MagickFalse)
3765 (void) FormatMagickSize(cache_info->length,MagickFalse,"B",
3766 MagickPathExtent,format);
3767 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3769 (void) FormatLocaleString(message,MagickPathExtent,
3770 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3771 cache_info->cache_filename,cache_info->file,type,(double)
3772 cache_info->columns,(double) cache_info->rows,(double)
3773 cache_info->number_channels,format);
3774 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3776 return(status == 0 ? MagickFalse : MagickTrue);
3780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3784 + P e r s i s t P i x e l C a c h e %
3788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3790 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3791 % persistent pixel cache is one that resides on disk and is not destroyed
3792 % when the program exits.
3794 % The format of the PersistPixelCache() method is:
3796 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3797 % const MagickBooleanType attach,MagickOffsetType *offset,
3798 % ExceptionInfo *exception)
3800 % A description of each parameter follows:
3802 % o image: the image.
3804 % o filename: the persistent pixel cache filename.
3806 % o attach: A value other than zero initializes the persistent pixel cache.
3808 % o initialize: A value other than zero initializes the persistent pixel
3811 % o offset: the offset in the persistent cache to store pixels.
3813 % o exception: return any errors or warnings in this structure.
3816 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3817 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3818 ExceptionInfo *exception)
3821 *magick_restrict cache_info,
3822 *magick_restrict clone_info;
3830 assert(image != (Image *) NULL);
3831 assert(image->signature == MagickCoreSignature);
3832 if (image->debug != MagickFalse)
3833 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3834 assert(image->cache != (void *) NULL);
3835 assert(filename != (const char *) NULL);
3836 assert(offset != (MagickOffsetType *) NULL);
3837 page_size=GetMagickPageSize();
3838 cache_info=(CacheInfo *) image->cache;
3839 assert(cache_info->signature == MagickCoreSignature);
3840 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3841 CopyOpenCLBuffer(cache_info);
3843 if (attach != MagickFalse)
3846 Attach existing persistent pixel cache.
3848 if (image->debug != MagickFalse)
3849 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
3850 "attach persistent cache");
3851 (void) CopyMagickString(cache_info->cache_filename,filename,
3853 cache_info->type=DiskCache;
3854 cache_info->offset=(*offset);
3855 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
3856 return(MagickFalse);
3857 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3861 Clone persistent pixel cache.
3863 clone_info=(CacheInfo *) ClonePixelCache(cache_info);
3864 clone_info->type=DiskCache;
3865 (void) CopyMagickString(clone_info->cache_filename,filename,MagickPathExtent);
3866 clone_info->file=(-1);
3867 clone_info->storage_class=cache_info->storage_class;
3868 clone_info->colorspace=cache_info->colorspace;
3869 clone_info->alpha_trait=cache_info->alpha_trait;
3870 clone_info->read_mask=cache_info->read_mask;
3871 clone_info->write_mask=cache_info->write_mask;
3872 clone_info->rows=cache_info->rows;
3873 clone_info->columns=cache_info->columns;
3874 clone_info->number_channels=cache_info->number_channels;
3875 clone_info->metacontent_extent=cache_info->metacontent_extent;
3876 clone_info->mode=PersistMode;
3877 clone_info->length=cache_info->length;
3878 (void) memcpy(clone_info->channel_map,cache_info->channel_map,
3879 MaxPixelChannels*sizeof(*cache_info->channel_map));
3880 clone_info->offset=(*offset);
3881 status=ClonePixelCacheRepository(clone_info,cache_info,exception);
3882 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
3883 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
3888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3892 + 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 %
3896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3898 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
3899 % defined by the region rectangle and returns a pointer to the region. This
3900 % region is subsequently transferred from the pixel cache with
3901 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3902 % pixels are transferred, otherwise a NULL is returned.
3904 % The format of the QueueAuthenticPixelCacheNexus() method is:
3906 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
3907 % const ssize_t y,const size_t columns,const size_t rows,
3908 % const MagickBooleanType clone,NexusInfo *nexus_info,
3909 % ExceptionInfo *exception)
3911 % A description of each parameter follows:
3913 % o image: the image.
3915 % o x,y,columns,rows: These values define the perimeter of a region of
3918 % o nexus_info: the cache nexus to set.
3920 % o clone: clone the pixel cache.
3922 % o exception: return any errors or warnings in this structure.
3925 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
3926 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3927 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
3930 *magick_restrict cache_info;
3939 *magick_restrict pixels;
3945 Validate pixel cache geometry.
3947 assert(image != (const Image *) NULL);
3948 assert(image->signature == MagickCoreSignature);
3949 assert(image->cache != (Cache) NULL);
3950 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
3951 if (cache_info == (Cache) NULL)
3952 return((Quantum *) NULL);
3953 assert(cache_info->signature == MagickCoreSignature);
3954 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
3955 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
3956 (y >= (ssize_t) cache_info->rows))
3958 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3959 "PixelsAreNotAuthentic","`%s'",image->filename);
3960 return((Quantum *) NULL);
3962 offset=(MagickOffsetType) y*cache_info->columns+x;
3964 return((Quantum *) NULL);
3965 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3966 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
3967 if ((MagickSizeType) offset >= number_pixels)
3968 return((Quantum *) NULL);
3974 region.width=columns;
3976 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,®ion,nexus_info,
3982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3986 + 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 %
3990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3992 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
3993 % defined by the region rectangle and returns a pointer to the region. This
3994 % region is subsequently transferred from the pixel cache with
3995 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
3996 % pixels are transferred, otherwise a NULL is returned.
3998 % The format of the QueueAuthenticPixelsCache() method is:
4000 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4001 % const ssize_t y,const size_t columns,const size_t rows,
4002 % ExceptionInfo *exception)
4004 % A description of each parameter follows:
4006 % o image: the image.
4008 % o x,y,columns,rows: These values define the perimeter of a region of
4011 % o exception: return any errors or warnings in this structure.
4014 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4015 const ssize_t y,const size_t columns,const size_t rows,
4016 ExceptionInfo *exception)
4019 *magick_restrict cache_info;
4022 id = GetOpenMPThreadId();
4025 *magick_restrict pixels;
4027 assert(image != (const Image *) NULL);
4028 assert(image->signature == MagickCoreSignature);
4029 assert(image->cache != (Cache) NULL);
4030 cache_info=(CacheInfo *) image->cache;
4031 assert(cache_info->signature == MagickCoreSignature);
4032 assert(id < (int) cache_info->number_threads);
4033 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4034 cache_info->nexus_info[id],exception);
4039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4043 % Q u e u e A u t h e n t i c P i x e l s %
4047 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4049 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4050 % successfully initialized a pointer to a Quantum array representing the
4051 % region is returned, otherwise NULL is returned. The returned pointer may
4052 % point to a temporary working buffer for the pixels or it may point to the
4053 % final location of the pixels in memory.
4055 % Write-only access means that any existing pixel values corresponding to
4056 % the region are ignored. This is useful if the initial image is being
4057 % created from scratch, or if the existing pixel values are to be
4058 % completely replaced without need to refer to their pre-existing values.
4059 % The application is free to read and write the pixel buffer returned by
4060 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4061 % initialize the pixel array values. Initializing pixel array values is the
4062 % application's responsibility.
4064 % Performance is maximized if the selected region is part of one row, or
4065 % one or more full rows, since then there is opportunity to access the
4066 % pixels in-place (without a copy) if the image is in memory, or in a
4067 % memory-mapped file. The returned pointer must *never* be deallocated
4070 % Pixels accessed via the returned pointer represent a simple array of type
4071 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4072 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4073 % obtain the meta-content (of type void) corresponding to the region.
4074 % Once the Quantum (and/or Quantum) array has been updated, the
4075 % changes must be saved back to the underlying image using
4076 % SyncAuthenticPixels() or they may be lost.
4078 % The format of the QueueAuthenticPixels() method is:
4080 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4081 % const ssize_t y,const size_t columns,const size_t rows,
4082 % ExceptionInfo *exception)
4084 % A description of each parameter follows:
4086 % o image: the image.
4088 % o x,y,columns,rows: These values define the perimeter of a region of
4091 % o exception: return any errors or warnings in this structure.
4094 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4095 const ssize_t y,const size_t columns,const size_t rows,
4096 ExceptionInfo *exception)
4099 *magick_restrict cache_info;
4102 id = GetOpenMPThreadId();
4105 *magick_restrict pixels;
4107 assert(image != (Image *) NULL);
4108 assert(image->signature == MagickCoreSignature);
4109 assert(image->cache != (Cache) NULL);
4110 cache_info=(CacheInfo *) image->cache;
4111 assert(cache_info->signature == MagickCoreSignature);
4112 if (cache_info->methods.queue_authentic_pixels_handler !=
4113 (QueueAuthenticPixelsHandler) NULL)
4115 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4116 columns,rows,exception);
4119 assert(id < (int) cache_info->number_threads);
4120 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4121 cache_info->nexus_info[id],exception);
4126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4130 + 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 %
4134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4136 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4139 % The format of the ReadPixelCacheMetacontent() method is:
4141 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4142 % NexusInfo *nexus_info,ExceptionInfo *exception)
4144 % A description of each parameter follows:
4146 % o cache_info: the pixel cache.
4148 % o nexus_info: the cache nexus to read the metacontent.
4150 % o exception: return any errors or warnings in this structure.
4154 static inline MagickOffsetType ReadPixelCacheRegion(
4155 const CacheInfo *magick_restrict cache_info,const MagickOffsetType offset,
4156 const MagickSizeType length,unsigned char *magick_restrict buffer)
4158 register MagickOffsetType
4164 #if !defined(MAGICKCORE_HAVE_PREAD)
4165 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4166 return((MagickOffsetType) -1);
4169 for (i=0; i < (MagickOffsetType) length; i+=count)
4171 #if !defined(MAGICKCORE_HAVE_PREAD)
4172 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4175 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,(size_t)
4176 SSIZE_MAX),(off_t) (offset+i));
4188 static MagickBooleanType ReadPixelCacheMetacontent(
4189 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4190 ExceptionInfo *exception)
4203 register unsigned char
4209 if (cache_info->metacontent_extent == 0)
4210 return(MagickFalse);
4211 if (nexus_info->authentic_pixel_cache != MagickFalse)
4213 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4214 nexus_info->region.x;
4215 length=(MagickSizeType) nexus_info->region.width*
4216 cache_info->metacontent_extent;
4217 extent=length*nexus_info->region.height;
4218 rows=nexus_info->region.height;
4220 q=(unsigned char *) nexus_info->metacontent;
4221 switch (cache_info->type)
4226 register unsigned char
4230 Read meta-content from memory.
4232 if ((cache_info->columns == nexus_info->region.width) &&
4233 (extent == (MagickSizeType) ((size_t) extent)))
4238 p=(unsigned char *) cache_info->metacontent+offset*
4239 cache_info->metacontent_extent;
4240 for (y=0; y < (ssize_t) rows; y++)
4242 (void) memcpy(q,p,(size_t) length);
4243 p+=cache_info->metacontent_extent*cache_info->columns;
4244 q+=cache_info->metacontent_extent*nexus_info->region.width;
4251 Read meta content from disk.
4253 LockSemaphoreInfo(cache_info->file_semaphore);
4254 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4256 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4257 cache_info->cache_filename);
4258 UnlockSemaphoreInfo(cache_info->file_semaphore);
4259 return(MagickFalse);
4261 if ((cache_info->columns == nexus_info->region.width) &&
4262 (extent <= MagickMaxBufferExtent))
4267 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4268 for (y=0; y < (ssize_t) rows; y++)
4270 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4271 cache_info->number_channels*sizeof(Quantum)+offset*
4272 cache_info->metacontent_extent,length,(unsigned char *) q);
4273 if (count != (MagickOffsetType) length)
4275 offset+=cache_info->columns;
4276 q+=cache_info->metacontent_extent*nexus_info->region.width;
4278 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4279 (void) ClosePixelCacheOnDisk(cache_info);
4280 UnlockSemaphoreInfo(cache_info->file_semaphore);
4283 case DistributedCache:
4289 Read metacontent from distributed cache.
4291 LockSemaphoreInfo(cache_info->file_semaphore);
4292 region=nexus_info->region;
4293 if ((cache_info->columns != nexus_info->region.width) ||
4294 (extent > MagickMaxBufferExtent))
4301 for (y=0; y < (ssize_t) rows; y++)
4303 count=ReadDistributePixelCacheMetacontent((DistributeCacheInfo *)
4304 cache_info->server_info,®ion,length,(unsigned char *) q);
4305 if (count != (MagickOffsetType) length)
4307 q+=cache_info->metacontent_extent*nexus_info->region.width;
4310 UnlockSemaphoreInfo(cache_info->file_semaphore);
4316 if (y < (ssize_t) rows)
4318 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4319 cache_info->cache_filename);
4320 return(MagickFalse);
4322 if ((cache_info->debug != MagickFalse) &&
4323 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4324 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4325 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4326 nexus_info->region.width,(double) nexus_info->region.height,(double)
4327 nexus_info->region.x,(double) nexus_info->region.y);
4332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4336 + R e a d P i x e l C a c h e P i x e l s %
4340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4342 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4345 % The format of the ReadPixelCachePixels() method is:
4347 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4348 % NexusInfo *nexus_info,ExceptionInfo *exception)
4350 % A description of each parameter follows:
4352 % o cache_info: the pixel cache.
4354 % o nexus_info: the cache nexus to read the pixels.
4356 % o exception: return any errors or warnings in this structure.
4359 static MagickBooleanType ReadPixelCachePixels(
4360 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
4361 ExceptionInfo *exception)
4381 if (nexus_info->authentic_pixel_cache != MagickFalse)
4383 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns;
4384 if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4385 return(MagickFalse);
4386 offset+=nexus_info->region.x;
4387 number_channels=cache_info->number_channels;
4388 length=(MagickSizeType) number_channels*nexus_info->region.width*
4390 if ((length/number_channels/sizeof(Quantum)) != nexus_info->region.width)
4391 return(MagickFalse);
4392 rows=nexus_info->region.height;
4394 if ((extent == 0) || ((extent/length) != rows))
4395 return(MagickFalse);
4397 q=nexus_info->pixels;
4398 switch (cache_info->type)
4407 Read pixels from memory.
4409 if ((cache_info->columns == nexus_info->region.width) &&
4410 (extent == (MagickSizeType) ((size_t) extent)))
4415 p=cache_info->pixels+offset*cache_info->number_channels;
4416 for (y=0; y < (ssize_t) rows; y++)
4418 (void) memcpy(q,p,(size_t) length);
4419 p+=cache_info->number_channels*cache_info->columns;
4420 q+=cache_info->number_channels*nexus_info->region.width;
4427 Read pixels from disk.
4429 LockSemaphoreInfo(cache_info->file_semaphore);
4430 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4432 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4433 cache_info->cache_filename);
4434 UnlockSemaphoreInfo(cache_info->file_semaphore);
4435 return(MagickFalse);
4437 if ((cache_info->columns == nexus_info->region.width) &&
4438 (extent <= MagickMaxBufferExtent))
4443 for (y=0; y < (ssize_t) rows; y++)
4445 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4446 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4447 if (count != (MagickOffsetType) length)
4449 offset+=cache_info->columns;
4450 q+=cache_info->number_channels*nexus_info->region.width;
4452 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4453 (void) ClosePixelCacheOnDisk(cache_info);
4454 UnlockSemaphoreInfo(cache_info->file_semaphore);
4457 case DistributedCache:
4463 Read pixels from distributed cache.
4465 LockSemaphoreInfo(cache_info->file_semaphore);
4466 region=nexus_info->region;
4467 if ((cache_info->columns != nexus_info->region.width) ||
4468 (extent > MagickMaxBufferExtent))
4475 for (y=0; y < (ssize_t) rows; y++)
4477 count=ReadDistributePixelCachePixels((DistributeCacheInfo *)
4478 cache_info->server_info,®ion,length,(unsigned char *) q);
4479 if (count != (MagickOffsetType) length)
4481 q+=cache_info->number_channels*nexus_info->region.width;
4484 UnlockSemaphoreInfo(cache_info->file_semaphore);
4490 if (y < (ssize_t) rows)
4492 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4493 cache_info->cache_filename);
4494 return(MagickFalse);
4496 if ((cache_info->debug != MagickFalse) &&
4497 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4498 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4499 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4500 nexus_info->region.width,(double) nexus_info->region.height,(double)
4501 nexus_info->region.x,(double) nexus_info->region.y);
4506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4510 + R e f e r e n c e P i x e l C a c h e %
4514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4516 % ReferencePixelCache() increments the reference count associated with the
4517 % pixel cache returning a pointer to the cache.
4519 % The format of the ReferencePixelCache method is:
4521 % Cache ReferencePixelCache(Cache cache_info)
4523 % A description of each parameter follows:
4525 % o cache_info: the pixel cache.
4528 MagickPrivate Cache ReferencePixelCache(Cache cache)
4531 *magick_restrict cache_info;
4533 assert(cache != (Cache *) NULL);
4534 cache_info=(CacheInfo *) cache;
4535 assert(cache_info->signature == MagickCoreSignature);
4536 LockSemaphoreInfo(cache_info->semaphore);
4537 cache_info->reference_count++;
4538 UnlockSemaphoreInfo(cache_info->semaphore);
4543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4547 + R e s e t P i x e l C a c h e C h a n n e l s %
4551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4553 % ResetPixelCacheChannels() resets the pixel cache channels.
4555 % The format of the ResetPixelCacheChannels method is:
4557 % void ResetPixelCacheChannels(Image *)
4559 % A description of each parameter follows:
4561 % o image: the image.
4564 MagickPrivate void ResetPixelCacheChannels(Image *image)
4567 *magick_restrict cache_info;
4569 assert(image != (const Image *) NULL);
4570 assert(image->signature == MagickCoreSignature);
4571 assert(image->cache != (Cache) NULL);
4572 cache_info=(CacheInfo *) image->cache;
4573 assert(cache_info->signature == MagickCoreSignature);
4574 cache_info->number_channels=GetPixelChannels(image);
4578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4582 + R e s e t P i x e l C a c h e E p o c h %
4586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4588 % ResetPixelCacheEpoch() resets the pixel cache epoch.
4590 % The format of the ResetPixelCacheEpoch method is:
4592 % void ResetPixelCacheEpoch(void)
4595 MagickPrivate void ResetPixelCacheEpoch(void)
4601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4605 + S e t P i x e l C a c h e M e t h o d s %
4609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4611 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4613 % The format of the SetPixelCacheMethods() method is:
4615 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4617 % A description of each parameter follows:
4619 % o cache: the pixel cache.
4621 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4624 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4627 *magick_restrict cache_info;
4629 GetOneAuthenticPixelFromHandler
4630 get_one_authentic_pixel_from_handler;
4632 GetOneVirtualPixelFromHandler
4633 get_one_virtual_pixel_from_handler;
4636 Set cache pixel methods.
4638 assert(cache != (Cache) NULL);
4639 assert(cache_methods != (CacheMethods *) NULL);
4640 cache_info=(CacheInfo *) cache;
4641 assert(cache_info->signature == MagickCoreSignature);
4642 if (cache_info->debug != MagickFalse)
4643 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4644 cache_info->filename);
4645 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4646 cache_info->methods.get_virtual_pixel_handler=
4647 cache_methods->get_virtual_pixel_handler;
4648 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4649 cache_info->methods.destroy_pixel_handler=
4650 cache_methods->destroy_pixel_handler;
4651 if (cache_methods->get_virtual_metacontent_from_handler !=
4652 (GetVirtualMetacontentFromHandler) NULL)
4653 cache_info->methods.get_virtual_metacontent_from_handler=
4654 cache_methods->get_virtual_metacontent_from_handler;
4655 if (cache_methods->get_authentic_pixels_handler !=
4656 (GetAuthenticPixelsHandler) NULL)
4657 cache_info->methods.get_authentic_pixels_handler=
4658 cache_methods->get_authentic_pixels_handler;
4659 if (cache_methods->queue_authentic_pixels_handler !=
4660 (QueueAuthenticPixelsHandler) NULL)
4661 cache_info->methods.queue_authentic_pixels_handler=
4662 cache_methods->queue_authentic_pixels_handler;
4663 if (cache_methods->sync_authentic_pixels_handler !=
4664 (SyncAuthenticPixelsHandler) NULL)
4665 cache_info->methods.sync_authentic_pixels_handler=
4666 cache_methods->sync_authentic_pixels_handler;
4667 if (cache_methods->get_authentic_pixels_from_handler !=
4668 (GetAuthenticPixelsFromHandler) NULL)
4669 cache_info->methods.get_authentic_pixels_from_handler=
4670 cache_methods->get_authentic_pixels_from_handler;
4671 if (cache_methods->get_authentic_metacontent_from_handler !=
4672 (GetAuthenticMetacontentFromHandler) NULL)
4673 cache_info->methods.get_authentic_metacontent_from_handler=
4674 cache_methods->get_authentic_metacontent_from_handler;
4675 get_one_virtual_pixel_from_handler=
4676 cache_info->methods.get_one_virtual_pixel_from_handler;
4677 if (get_one_virtual_pixel_from_handler !=
4678 (GetOneVirtualPixelFromHandler) NULL)
4679 cache_info->methods.get_one_virtual_pixel_from_handler=
4680 cache_methods->get_one_virtual_pixel_from_handler;
4681 get_one_authentic_pixel_from_handler=
4682 cache_methods->get_one_authentic_pixel_from_handler;
4683 if (get_one_authentic_pixel_from_handler !=
4684 (GetOneAuthenticPixelFromHandler) NULL)
4685 cache_info->methods.get_one_authentic_pixel_from_handler=
4686 cache_methods->get_one_authentic_pixel_from_handler;
4690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4694 + S e t P i x e l C a c h e N e x u s P i x e l s %
4698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4700 % SetPixelCacheNexusPixels() defines the region of the cache for the
4701 % specified cache nexus.
4703 % The format of the SetPixelCacheNexusPixels() method is:
4705 % Quantum SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4706 % const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4707 % ExceptionInfo *exception)
4709 % A description of each parameter follows:
4711 % o cache_info: the pixel cache.
4713 % o mode: ReadMode, WriteMode, or IOMode.
4715 % o region: A pointer to the RectangleInfo structure that defines the
4716 % region of this particular cache nexus.
4718 % o nexus_info: the cache nexus to set.
4720 % o exception: return any errors or warnings in this structure.
4724 static inline MagickBooleanType AcquireCacheNexusPixels(
4725 const CacheInfo *magick_restrict cache_info,NexusInfo *nexus_info,
4726 ExceptionInfo *exception)
4728 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4729 return(MagickFalse);
4730 if (cache_anonymous_memory <= 0)
4732 nexus_info->mapped=MagickFalse;
4733 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4734 (size_t) nexus_info->length));
4735 if (nexus_info->cache != (Quantum *) NULL)
4736 (void) ResetMagickMemory(nexus_info->cache,0,(size_t)
4737 nexus_info->length);
4741 nexus_info->mapped=MagickTrue;
4742 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4743 nexus_info->length);
4745 if (nexus_info->cache == (Quantum *) NULL)
4747 (void) ThrowMagickException(exception,GetMagickModule(),
4748 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4749 cache_info->filename);
4750 return(MagickFalse);
4755 static inline MagickBooleanType IsPixelCacheAuthentic(
4756 const CacheInfo *magick_restrict cache_info,
4757 const NexusInfo *magick_restrict nexus_info)
4766 Does nexus pixels point directly to in-core cache pixels or is it buffered?
4768 if (cache_info->type == PingCache)
4770 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4771 nexus_info->region.x;
4772 status=nexus_info->pixels == (cache_info->pixels+offset*
4773 cache_info->number_channels) ? MagickTrue : MagickFalse;
4777 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4780 if (mode == ReadMode)
4782 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4785 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4788 static Quantum *SetPixelCacheNexusPixels(const CacheInfo *cache_info,
4789 const MapMode mode,const RectangleInfo *region,NexusInfo *nexus_info,
4790 ExceptionInfo *exception)
4799 assert(cache_info != (const CacheInfo *) NULL);
4800 assert(cache_info->signature == MagickCoreSignature);
4801 if (cache_info->type == UndefinedCache)
4802 return((Quantum *) NULL);
4803 nexus_info->region=(*region);
4804 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4810 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4811 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4812 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4813 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4814 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4815 ((nexus_info->region.width == cache_info->columns) ||
4816 ((nexus_info->region.width % cache_info->columns) == 0)))))
4822 Pixels are accessed directly from memory.
4824 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4825 nexus_info->region.x;
4826 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4828 nexus_info->metacontent=(void *) NULL;
4829 if (cache_info->metacontent_extent != 0)
4830 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4831 offset*cache_info->metacontent_extent;
4832 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4833 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4835 return(nexus_info->pixels);
4839 Pixels are stored in a staging region until they are synced to the cache.
4841 number_pixels=(MagickSizeType) nexus_info->region.width*
4842 nexus_info->region.height;
4843 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4844 if (cache_info->metacontent_extent != 0)
4845 length+=number_pixels*cache_info->metacontent_extent;
4846 if (nexus_info->cache == (Quantum *) NULL)
4848 nexus_info->length=length;
4849 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4850 if (status == MagickFalse)
4852 nexus_info->length=0;
4853 return((Quantum *) NULL);
4857 if (nexus_info->length < length)
4859 RelinquishCacheNexusPixels(nexus_info);
4860 nexus_info->length=length;
4861 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4862 if (status == MagickFalse)
4864 nexus_info->length=0;
4865 return((Quantum *) NULL);
4868 nexus_info->pixels=nexus_info->cache;
4869 nexus_info->metacontent=(void *) NULL;
4870 if (cache_info->metacontent_extent != 0)
4871 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4872 cache_info->number_channels);
4873 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4874 nexus_info->authentic_pixel_cache=IsPixelCacheAuthentic(cache_info,
4876 return(nexus_info->pixels);
4880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4884 % 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 %
4888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4890 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4891 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4892 % access that is outside the boundaries of the image cache.
4894 % The format of the SetPixelCacheVirtualMethod() method is:
4896 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4897 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4899 % A description of each parameter follows:
4901 % o image: the image.
4903 % o virtual_pixel_method: choose the type of virtual pixel.
4905 % o exception: return any errors or warnings in this structure.
4909 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4910 ExceptionInfo *exception)
4913 *magick_restrict cache_info;
4916 *magick_restrict image_view;
4924 assert(image != (Image *) NULL);
4925 assert(image->signature == MagickCoreSignature);
4926 if (image->debug != MagickFalse)
4927 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4928 assert(image->cache != (Cache) NULL);
4929 cache_info=(CacheInfo *) image->cache;
4930 assert(cache_info->signature == MagickCoreSignature);
4931 image->alpha_trait=BlendPixelTrait;
4933 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4934 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4935 #pragma omp parallel for schedule(static,4) shared(status) \
4936 magick_threads(image,image,1,1)
4938 for (y=0; y < (ssize_t) image->rows; y++)
4946 if (status == MagickFalse)
4948 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4949 if (q == (Quantum *) NULL)
4954 for (x=0; x < (ssize_t) image->columns; x++)
4956 SetPixelAlpha(image,alpha,q);
4957 q+=GetPixelChannels(image);
4959 status=SyncCacheViewAuthenticPixels(image_view,exception);
4961 image_view=DestroyCacheView(image_view);
4965 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4966 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4969 *magick_restrict cache_info;
4974 assert(image != (Image *) NULL);
4975 assert(image->signature == MagickCoreSignature);
4976 if (image->debug != MagickFalse)
4977 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4978 assert(image->cache != (Cache) NULL);
4979 cache_info=(CacheInfo *) image->cache;
4980 assert(cache_info->signature == MagickCoreSignature);
4981 method=cache_info->virtual_pixel_method;
4982 cache_info->virtual_pixel_method=virtual_pixel_method;
4983 if ((image->columns != 0) && (image->rows != 0))
4984 switch (virtual_pixel_method)
4986 case BackgroundVirtualPixelMethod:
4988 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
4989 (image->alpha_trait == UndefinedPixelTrait))
4990 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4991 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4992 (IsGrayColorspace(image->colorspace) != MagickFalse))
4993 (void) SetImageColorspace(image,sRGBColorspace,exception);
4996 case TransparentVirtualPixelMethod:
4998 if (image->alpha_trait == UndefinedPixelTrait)
4999 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5008 #if defined(MAGICKCORE_OPENCL_SUPPORT)
5010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5014 + 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 %
5018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5020 % SyncAuthenticOpenCLBuffer() makes sure that all the OpenCL operations have
5021 % been completed and updates the host memory.
5023 % The format of the SyncAuthenticOpenCLBuffer() method is:
5025 % void SyncAuthenticOpenCLBuffer(const Image *image)
5027 % A description of each parameter follows:
5029 % o image: the image.
5033 static void CopyOpenCLBuffer(CacheInfo *magick_restrict cache_info)
5035 assert(cache_info != (CacheInfo *) NULL);
5036 assert(cache_info->signature == MagickCoreSignature);
5037 if ((cache_info->type != MemoryCache) ||
5038 (cache_info->opencl == (MagickCLCacheInfo) NULL))
5041 Ensure single threaded access to OpenCL environment.
5043 LockSemaphoreInfo(cache_info->semaphore);
5044 cache_info->opencl=(MagickCLCacheInfo) CopyMagickCLCacheInfo(
5045 cache_info->opencl);
5046 UnlockSemaphoreInfo(cache_info->semaphore);
5049 MagickPrivate void SyncAuthenticOpenCLBuffer(const Image *image)
5052 *magick_restrict cache_info;
5054 assert(image != (const Image *) NULL);
5055 cache_info=(CacheInfo *) image->cache;
5056 CopyOpenCLBuffer(cache_info);
5061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5065 + 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 %
5069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5071 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5072 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5073 % is synced, otherwise MagickFalse.
5075 % The format of the SyncAuthenticPixelCacheNexus() method is:
5077 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5078 % NexusInfo *nexus_info,ExceptionInfo *exception)
5080 % A description of each parameter follows:
5082 % o image: the image.
5084 % o nexus_info: the cache nexus to sync.
5086 % o exception: return any errors or warnings in this structure.
5089 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5090 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5093 *magick_restrict cache_info;
5099 Transfer pixels to the cache.
5101 assert(image != (Image *) NULL);
5102 assert(image->signature == MagickCoreSignature);
5103 if (image->cache == (Cache) NULL)
5104 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5105 cache_info=(CacheInfo *) image->cache;
5106 assert(cache_info->signature == MagickCoreSignature);
5107 if (cache_info->type == UndefinedCache)
5108 return(MagickFalse);
5109 if (nexus_info->authentic_pixel_cache != MagickFalse)
5111 image->taint=MagickTrue;
5114 assert(cache_info->signature == MagickCoreSignature);
5115 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5116 if ((cache_info->metacontent_extent != 0) &&
5117 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5118 return(MagickFalse);
5119 if (status != MagickFalse)
5120 image->taint=MagickTrue;
5125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5129 + S y n c A u t h e n t i c P i x e l C a c h e %
5133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5135 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5136 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5137 % otherwise MagickFalse.
5139 % The format of the SyncAuthenticPixelsCache() method is:
5141 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5142 % ExceptionInfo *exception)
5144 % A description of each parameter follows:
5146 % o image: the image.
5148 % o exception: return any errors or warnings in this structure.
5151 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5152 ExceptionInfo *exception)
5155 *magick_restrict cache_info;
5158 id = GetOpenMPThreadId();
5163 assert(image != (Image *) NULL);
5164 assert(image->signature == MagickCoreSignature);
5165 assert(image->cache != (Cache) NULL);
5166 cache_info=(CacheInfo *) image->cache;
5167 assert(cache_info->signature == MagickCoreSignature);
5168 assert(id < (int) cache_info->number_threads);
5169 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5179 % S y n c A u t h e n t i c P i x e l s %
5183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5185 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5186 % The method returns MagickTrue if the pixel region is flushed, otherwise
5189 % The format of the SyncAuthenticPixels() method is:
5191 % MagickBooleanType SyncAuthenticPixels(Image *image,
5192 % ExceptionInfo *exception)
5194 % A description of each parameter follows:
5196 % o image: the image.
5198 % o exception: return any errors or warnings in this structure.
5201 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5202 ExceptionInfo *exception)
5205 *magick_restrict cache_info;
5208 id = GetOpenMPThreadId();
5213 assert(image != (Image *) NULL);
5214 assert(image->signature == MagickCoreSignature);
5215 assert(image->cache != (Cache) NULL);
5216 cache_info=(CacheInfo *) image->cache;
5217 assert(cache_info->signature == MagickCoreSignature);
5218 if (cache_info->methods.sync_authentic_pixels_handler !=
5219 (SyncAuthenticPixelsHandler) NULL)
5221 status=cache_info->methods.sync_authentic_pixels_handler(image,
5225 assert(id < (int) cache_info->number_threads);
5226 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5236 + S y n c I m a g e P i x e l C a c h e %
5240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5242 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5243 % The method returns MagickTrue if the pixel region is flushed, otherwise
5246 % The format of the SyncImagePixelCache() method is:
5248 % MagickBooleanType SyncImagePixelCache(Image *image,
5249 % ExceptionInfo *exception)
5251 % A description of each parameter follows:
5253 % o image: the image.
5255 % o exception: return any errors or warnings in this structure.
5258 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5259 ExceptionInfo *exception)
5262 *magick_restrict cache_info;
5264 assert(image != (Image *) NULL);
5265 assert(exception != (ExceptionInfo *) NULL);
5266 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5267 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5275 + 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 %
5279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5281 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5282 % of the pixel cache.
5284 % The format of the WritePixelCacheMetacontent() method is:
5286 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5287 % NexusInfo *nexus_info,ExceptionInfo *exception)
5289 % A description of each parameter follows:
5291 % o cache_info: the pixel cache.
5293 % o nexus_info: the cache nexus to write the meta-content.
5295 % o exception: return any errors or warnings in this structure.
5298 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5299 NexusInfo *magick_restrict nexus_info,ExceptionInfo *exception)
5309 register const unsigned char
5318 if (cache_info->metacontent_extent == 0)
5319 return(MagickFalse);
5320 if (nexus_info->authentic_pixel_cache != MagickFalse)
5322 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5323 nexus_info->region.x;
5324 length=(MagickSizeType) nexus_info->region.width*
5325 cache_info->metacontent_extent;
5326 extent=(MagickSizeType) length*nexus_info->region.height;
5327 rows=nexus_info->region.height;
5329 p=(unsigned char *) nexus_info->metacontent;
5330 switch (cache_info->type)
5335 register unsigned char
5339 Write associated pixels to memory.
5341 if ((cache_info->columns == nexus_info->region.width) &&
5342 (extent == (MagickSizeType) ((size_t) extent)))
5347 q=(unsigned char *) cache_info->metacontent+offset*
5348 cache_info->metacontent_extent;
5349 for (y=0; y < (ssize_t) rows; y++)
5351 (void) memcpy(q,p,(size_t) length);
5352 p+=nexus_info->region.width*cache_info->metacontent_extent;
5353 q+=cache_info->columns*cache_info->metacontent_extent;
5360 Write associated pixels to disk.
5362 LockSemaphoreInfo(cache_info->file_semaphore);
5363 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5365 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5366 cache_info->cache_filename);
5367 UnlockSemaphoreInfo(cache_info->file_semaphore);
5368 return(MagickFalse);
5370 if ((cache_info->columns == nexus_info->region.width) &&
5371 (extent <= MagickMaxBufferExtent))
5376 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5377 for (y=0; y < (ssize_t) rows; y++)
5379 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5380 cache_info->number_channels*sizeof(Quantum)+offset*
5381 cache_info->metacontent_extent,length,(const unsigned char *) p);
5382 if (count != (MagickOffsetType) length)
5384 p+=cache_info->metacontent_extent*nexus_info->region.width;
5385 offset+=cache_info->columns;
5387 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5388 (void) ClosePixelCacheOnDisk(cache_info);
5389 UnlockSemaphoreInfo(cache_info->file_semaphore);
5392 case DistributedCache:
5398 Write metacontent to distributed cache.
5400 LockSemaphoreInfo(cache_info->file_semaphore);
5401 region=nexus_info->region;
5402 if ((cache_info->columns != nexus_info->region.width) ||
5403 (extent > MagickMaxBufferExtent))
5410 for (y=0; y < (ssize_t) rows; y++)
5412 count=WriteDistributePixelCacheMetacontent((DistributeCacheInfo *)
5413 cache_info->server_info,®ion,length,(const unsigned char *) p);
5414 if (count != (MagickOffsetType) length)
5416 p+=cache_info->metacontent_extent*nexus_info->region.width;
5419 UnlockSemaphoreInfo(cache_info->file_semaphore);
5425 if (y < (ssize_t) rows)
5427 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5428 cache_info->cache_filename);
5429 return(MagickFalse);
5431 if ((cache_info->debug != MagickFalse) &&
5432 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5433 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5434 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5435 nexus_info->region.width,(double) nexus_info->region.height,(double)
5436 nexus_info->region.x,(double) nexus_info->region.y);
5441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5445 + W r i t e C a c h e P i x e l s %
5449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5451 % WritePixelCachePixels() writes image pixels to the specified region of the
5454 % The format of the WritePixelCachePixels() method is:
5456 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5457 % NexusInfo *nexus_info,ExceptionInfo *exception)
5459 % A description of each parameter follows:
5461 % o cache_info: the pixel cache.
5463 % o nexus_info: the cache nexus to write the pixels.
5465 % o exception: return any errors or warnings in this structure.
5468 static MagickBooleanType WritePixelCachePixels(
5469 CacheInfo *magick_restrict cache_info,NexusInfo *magick_restrict nexus_info,
5470 ExceptionInfo *exception)
5480 register const Quantum
5489 if (nexus_info->authentic_pixel_cache != MagickFalse)
5491 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5492 nexus_info->region.x;
5493 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5495 extent=length*nexus_info->region.height;
5496 rows=nexus_info->region.height;
5498 p=nexus_info->pixels;
5499 switch (cache_info->type)
5508 Write pixels to memory.
5510 if ((cache_info->columns == nexus_info->region.width) &&
5511 (extent == (MagickSizeType) ((size_t) extent)))
5516 q=cache_info->pixels+offset*cache_info->number_channels;
5517 for (y=0; y < (ssize_t) rows; y++)
5519 (void) memcpy(q,p,(size_t) length);
5520 p+=cache_info->number_channels*nexus_info->region.width;
5521 q+=cache_info->columns*cache_info->number_channels;
5528 Write pixels to disk.
5530 LockSemaphoreInfo(cache_info->file_semaphore);
5531 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5533 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5534 cache_info->cache_filename);
5535 UnlockSemaphoreInfo(cache_info->file_semaphore);
5536 return(MagickFalse);
5538 if ((cache_info->columns == nexus_info->region.width) &&
5539 (extent <= MagickMaxBufferExtent))
5544 for (y=0; y < (ssize_t) rows; y++)
5546 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5547 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5549 if (count != (MagickOffsetType) length)
5551 p+=cache_info->number_channels*nexus_info->region.width;
5552 offset+=cache_info->columns;
5554 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5555 (void) ClosePixelCacheOnDisk(cache_info);
5556 UnlockSemaphoreInfo(cache_info->file_semaphore);
5559 case DistributedCache:
5565 Write pixels to distributed cache.
5567 LockSemaphoreInfo(cache_info->file_semaphore);
5568 region=nexus_info->region;
5569 if ((cache_info->columns != nexus_info->region.width) ||
5570 (extent > MagickMaxBufferExtent))
5577 for (y=0; y < (ssize_t) rows; y++)
5579 count=WriteDistributePixelCachePixels((DistributeCacheInfo *)
5580 cache_info->server_info,®ion,length,(const unsigned char *) p);
5581 if (count != (MagickOffsetType) length)
5583 p+=cache_info->number_channels*nexus_info->region.width;
5586 UnlockSemaphoreInfo(cache_info->file_semaphore);
5592 if (y < (ssize_t) rows)
5594 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5595 cache_info->cache_filename);
5596 return(MagickFalse);
5598 if ((cache_info->debug != MagickFalse) &&
5599 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5600 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5601 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5602 nexus_info->region.width,(double) nexus_info->region.height,(double)
5603 nexus_info->region.x,(double) nexus_info->region.y);