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-2013 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 % http://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
120 Forward declarations.
122 #if defined(__cplusplus) || defined(c_plusplus)
127 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
131 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
132 const ssize_t,const size_t,const size_t,ExceptionInfo *),
133 *GetVirtualPixelsCache(const Image *);
136 *GetVirtualMetacontentFromCache(const Image *);
138 static MagickBooleanType
139 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
141 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
142 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
143 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
144 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
145 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
146 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
147 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
148 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *);
151 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
152 const size_t,ExceptionInfo *),
153 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
154 const size_t,ExceptionInfo *),
155 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
156 NexusInfo *,ExceptionInfo *) magick_hot_spot;
158 #if defined(__cplusplus) || defined(c_plusplus)
165 static volatile MagickBooleanType
166 instantiate_cache = MagickFalse;
169 *cache_semaphore = (SemaphoreInfo *) NULL;
172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 + A c q u i r e P i x e l C a c h e %
180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
182 % AcquirePixelCache() acquires a pixel cache.
184 % The format of the AcquirePixelCache() method is:
186 % Cache AcquirePixelCache(const size_t number_threads)
188 % A description of each parameter follows:
190 % o number_threads: the number of nexus threads.
193 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
201 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
202 if (cache_info == (CacheInfo *) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
205 cache_info->type=UndefinedCache;
206 cache_info->mode=IOMode;
207 cache_info->colorspace=sRGBColorspace;
208 cache_info->file=(-1);
209 cache_info->id=GetMagickThreadId();
210 cache_info->number_threads=number_threads;
211 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
212 cache_info->number_threads=GetOpenMPMaximumThreads();
213 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
214 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
215 if (cache_info->number_threads == 0)
216 cache_info->number_threads=1;
217 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
218 if (cache_info->nexus_info == (NexusInfo **) NULL)
219 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
220 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
221 if (synchronize != (const char *) NULL)
223 cache_info->synchronize=IsStringTrue(synchronize);
224 synchronize=DestroyString(synchronize);
226 cache_info->semaphore=AllocateSemaphoreInfo();
227 cache_info->reference_count=1;
228 cache_info->file_semaphore=AllocateSemaphoreInfo();
229 cache_info->debug=IsEventLogging();
230 cache_info->signature=MagickSignature;
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)
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=MagickSignature;
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)
315 assert(image != (const Image *) NULL);
316 assert(image->signature == MagickSignature);
317 assert(exception != (ExceptionInfo *) NULL);
318 assert(exception->signature == MagickSignature);
319 assert(image->cache != (Cache) NULL);
320 cache_info=(CacheInfo *) image->cache;
321 assert(cache_info->signature == MagickSignature);
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 AcquireSemaphoreInfo(&cache_semaphore);
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358 + C a c h e C o m p o n e n t T e r m i n u s %
362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
364 % CacheComponentTerminus() destroys the cache component.
366 % The format of the CacheComponentTerminus() method is:
368 % CacheComponentTerminus(void)
371 MagickPrivate void CacheComponentTerminus(void)
373 if (cache_semaphore == (SemaphoreInfo *) NULL)
374 AcquireSemaphoreInfo(&cache_semaphore);
375 LockSemaphoreInfo(cache_semaphore);
376 instantiate_cache=MagickFalse;
377 UnlockSemaphoreInfo(cache_semaphore);
378 DestroySemaphoreInfo(&cache_semaphore);
382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 + C l o n e P i x e l C a c h e %
390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392 % ClonePixelCache() clones a pixel cache.
394 % The format of the ClonePixelCache() method is:
396 % Cache ClonePixelCache(const Cache cache)
398 % A description of each parameter follows:
400 % o cache: the pixel cache.
403 MagickPrivate Cache ClonePixelCache(const Cache cache)
411 assert(cache != NULL);
412 cache_info=(const CacheInfo *) cache;
413 assert(cache_info->signature == MagickSignature);
414 if (cache_info->debug != MagickFalse)
415 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
416 cache_info->filename);
417 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
418 if (clone_info == (Cache) NULL)
419 return((Cache) NULL);
420 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
421 return((Cache ) clone_info);
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429 + C l o n e P i x e l C a c h e P i x e l s %
433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
434 % ClonePixelCachePixels() clones the source pixel cache to the destination
437 % The format of the ClonePixelCachePixels() method is:
439 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
440 % CacheInfo *source_info,ExceptionInfo *exception)
442 % A description of each parameter follows:
444 % o cache_info: the pixel cache.
446 % o source_info: the source pixel cache.
448 % o exception: return any errors or warnings in this structure.
452 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
458 if (cache_info->file != -1)
460 status=close(cache_info->file);
461 cache_info->file=(-1);
462 RelinquishMagickResource(FileResource,1);
464 return(status == -1 ? MagickFalse : MagickTrue);
467 static inline MagickSizeType MagickMax(const MagickSizeType x,
468 const MagickSizeType y)
475 static inline MagickSizeType MagickMin(const MagickSizeType x,
476 const MagickSizeType y)
483 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
490 Open pixel cache on disk.
492 if (cache_info->file != -1)
493 return(MagickTrue); /* cache already open */
494 if (*cache_info->cache_filename == '\0')
495 file=AcquireUniqueFileResource(cache_info->cache_filename);
501 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
506 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
507 O_BINARY | O_EXCL,S_MODE);
509 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
515 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
518 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
524 (void) AcquireMagickResource(FileResource,1);
525 cache_info->file=file;
526 cache_info->mode=mode;
530 static inline MagickOffsetType ReadPixelCacheRegion(
531 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
532 const MagickSizeType length,unsigned char *restrict buffer)
534 register MagickOffsetType
540 #if !defined(MAGICKCORE_HAVE_PREAD)
541 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
542 return((MagickOffsetType) -1);
545 for (i=0; i < (MagickOffsetType) length; i+=count)
547 #if !defined(MAGICKCORE_HAVE_PREAD)
548 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
549 (MagickSizeType) SSIZE_MAX));
551 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
552 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
564 static inline MagickOffsetType WritePixelCacheRegion(
565 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
566 const MagickSizeType length,const unsigned char *restrict buffer)
568 register MagickOffsetType
574 #if !defined(MAGICKCORE_HAVE_PWRITE)
575 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
576 return((MagickOffsetType) -1);
579 for (i=0; i < (MagickOffsetType) length; i+=count)
581 #if !defined(MAGICKCORE_HAVE_PWRITE)
582 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
583 (MagickSizeType) SSIZE_MAX));
585 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
586 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
598 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
599 CacheInfo *cache_info,ExceptionInfo *exception)
604 register MagickOffsetType
614 Clone pixel cache (both caches on disk).
616 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
618 if (blob == (unsigned char *) NULL)
620 (void) ThrowMagickException(exception,GetMagickModule(),
621 ResourceLimitError,"MemoryAllocationFailed","`%s'",
622 cache_info->filename);
625 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
627 blob=(unsigned char *) RelinquishMagickMemory(blob);
628 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
629 cache_info->cache_filename);
632 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
634 (void) ClosePixelCacheOnDisk(cache_info);
635 blob=(unsigned char *) RelinquishMagickMemory(blob);
636 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
637 clone_info->cache_filename);
641 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
643 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
644 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
648 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
649 cache_info->cache_filename);
652 length=(size_t) count;
653 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
654 if ((MagickSizeType) count != length)
656 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
657 clone_info->cache_filename);
661 (void) ClosePixelCacheOnDisk(clone_info);
662 (void) ClosePixelCacheOnDisk(cache_info);
663 blob=(unsigned char *) RelinquishMagickMemory(blob);
664 if (i < (MagickOffsetType) cache_info->length)
669 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
670 CacheInfo *cache_info,ExceptionInfo *exception)
675 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
678 Clone pixel cache (both caches in memory).
680 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
684 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
687 Clone pixel cache (one cache on disk, one in memory).
689 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
691 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
692 cache_info->cache_filename);
695 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
696 cache_info->length,(unsigned char *) clone_info->pixels);
697 (void) ClosePixelCacheOnDisk(cache_info);
698 if ((MagickSizeType) count != cache_info->length)
700 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
701 cache_info->cache_filename);
706 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
709 Clone pixel cache (one cache on disk, one in memory).
711 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
713 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
714 clone_info->cache_filename);
717 count=WritePixelCacheRegion(clone_info,clone_info->offset,
718 clone_info->length,(unsigned char *) cache_info->pixels);
719 (void) ClosePixelCacheOnDisk(clone_info);
720 if ((MagickSizeType) count != clone_info->length)
722 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
723 clone_info->cache_filename);
729 Clone pixel cache (both caches on disk).
731 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
734 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
735 CacheInfo *cache_info,ExceptionInfo *exception)
748 register unsigned char
761 Clone pixel cache (unoptimized).
763 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
764 clone_info->number_channels)*sizeof(Quantum),MagickMax(
765 cache_info->metacontent_extent,clone_info->metacontent_extent));
766 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
767 if (blob == (unsigned char *) NULL)
769 (void) ThrowMagickException(exception,GetMagickModule(),
770 ResourceLimitError,"MemoryAllocationFailed","`%s'",
771 cache_info->filename);
774 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
777 if (cache_info->type == DiskCache)
779 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
781 blob=(unsigned char *) RelinquishMagickMemory(blob);
782 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
783 cache_info->cache_filename);
786 cache_offset=cache_info->offset;
788 if (clone_info->type == DiskCache)
790 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
792 blob=(unsigned char *) RelinquishMagickMemory(blob);
793 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
794 clone_info->cache_filename);
797 clone_offset=clone_info->offset;
800 Clone pixel channels.
804 for (y=0; y < (ssize_t) cache_info->rows; y++)
806 for (x=0; x < (ssize_t) cache_info->columns; x++)
812 Read a set of pixel channels.
814 length=cache_info->number_channels*sizeof(Quantum);
815 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
816 p=(unsigned char *) cache_info->pixels+cache_offset;
819 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
820 if ((MagickSizeType) count != length)
823 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
824 cache_info->cache_filename);
828 cache_offset+=length;
829 if ((y < (ssize_t) clone_info->rows) &&
830 (x < (ssize_t) clone_info->columns))
831 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
843 Write a set of pixel channels.
845 channel=clone_info->channel_map[i].channel;
846 traits=cache_info->channel_map[channel].traits;
847 if (traits == UndefinedPixelTrait)
849 clone_offset+=sizeof(Quantum);
852 offset=cache_info->channel_map[channel].offset;
853 if ((clone_info->type == MemoryCache) ||
854 (clone_info->type == MapCache))
855 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
856 offset*sizeof(Quantum),sizeof(Quantum));
859 count=WritePixelCacheRegion(clone_info,clone_offset,
860 sizeof(Quantum),p+offset*sizeof(Quantum));
861 if ((MagickSizeType) count != sizeof(Quantum))
864 ThrowFileException(exception,CacheError,
865 "UnableToWritePixelCache",cache_info->cache_filename);
869 clone_offset+=sizeof(Quantum);
872 if (y < (ssize_t) clone_info->rows)
875 Set remaining columns as undefined.
877 length=clone_info->number_channels*sizeof(Quantum);
878 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
879 for ( ; x < (ssize_t) clone_info->columns; x++)
881 if ((clone_info->type == MemoryCache) ||
882 (clone_info->type == MapCache))
883 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
887 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
888 if ((MagickSizeType) count != length)
891 ThrowFileException(exception,CacheError,
892 "UnableToWritePixelCache",cache_info->cache_filename);
896 clone_offset+=length;
900 length=clone_info->number_channels*sizeof(Quantum);
901 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
902 for ( ; y < (ssize_t) clone_info->rows; y++)
905 Set remaining rows as undefined.
907 for (x=0; x < (ssize_t) clone_info->columns; x++)
909 if ((clone_info->type == MemoryCache) || (clone_info->type == MapCache))
910 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
914 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
915 if ((MagickSizeType) count != length)
918 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
919 cache_info->cache_filename);
923 clone_offset+=length;
926 if ((cache_info->metacontent_extent != 0) ||
927 (clone_info->metacontent_extent != 0))
932 for (y=0; y < (ssize_t) cache_info->rows; y++)
934 for (x=0; x < (ssize_t) cache_info->columns; x++)
937 Read a set of metacontent.
939 length=cache_info->metacontent_extent;
940 if ((cache_info->type == MemoryCache) ||
941 (cache_info->type == MapCache))
942 p=(unsigned char *) cache_info->pixels+cache_offset;
945 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
946 if ((MagickSizeType) count != length)
949 ThrowFileException(exception,CacheError,
950 "UnableToWritePixelCache",cache_info->cache_filename);
954 cache_offset+=length;
955 if ((y < (ssize_t) clone_info->rows) &&
956 (x < (ssize_t) clone_info->columns))
959 Write a set of metacontent.
961 length=clone_info->metacontent_extent;
962 if ((clone_info->type == MemoryCache) ||
963 (clone_info->type == MapCache))
964 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
968 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
969 if ((MagickSizeType) count != length)
972 ThrowFileException(exception,CacheError,
973 "UnableToWritePixelCache",cache_info->cache_filename);
977 clone_offset+=length;
980 length=clone_info->metacontent_extent;
981 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
982 for ( ; x < (ssize_t) clone_info->columns; x++)
985 Set remaining columns as undefined.
987 if ((clone_info->type == MemoryCache) ||
988 (clone_info->type == MapCache))
989 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
993 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
994 if ((MagickSizeType) count != length)
997 ThrowFileException(exception,CacheError,
998 "UnableToWritePixelCache",cache_info->cache_filename);
1002 clone_offset+=length;
1005 if (y < (ssize_t) clone_info->rows)
1008 Set remaining rows as undefined.
1010 length=clone_info->metacontent_extent;
1011 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1012 for ( ; y < (ssize_t) clone_info->rows; y++)
1014 for (x=0; x < (ssize_t) clone_info->columns; x++)
1016 if ((clone_info->type == MemoryCache) ||
1017 (clone_info->type == MapCache))
1018 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1022 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1024 if ((MagickSizeType) count != length)
1027 ThrowFileException(exception,CacheError,
1028 "UnableToWritePixelCache",cache_info->cache_filename);
1032 clone_offset+=length;
1037 if (clone_info->type == DiskCache)
1038 (void) ClosePixelCacheOnDisk(clone_info);
1039 if (cache_info->type == DiskCache)
1040 (void) ClosePixelCacheOnDisk(cache_info);
1041 blob=(unsigned char *) RelinquishMagickMemory(blob);
1045 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1046 CacheInfo *cache_info,ExceptionInfo *exception)
1052 if (cache_info->debug != MagickFalse)
1055 message[MaxTextExtent];
1057 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
1058 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
1059 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
1060 (void) LogMagickEvent(CacheEvent,GetMagickModule(),message);
1062 if (cache_info->type == PingCache)
1064 if ((cache_info->type == DistributedCache) ||
1065 (clone_info->type == DistributedCache))
1066 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1067 p=cache_info->channel_map;
1068 q=clone_info->channel_map;
1069 if ((cache_info->columns == clone_info->columns) &&
1070 (cache_info->rows == clone_info->rows) &&
1071 (cache_info->number_channels == clone_info->number_channels) &&
1072 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1073 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1074 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1075 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1083 + C l o n e P i x e l C a c h e M e t h o d s %
1087 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1089 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1092 % The format of the ClonePixelCacheMethods() method is:
1094 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1096 % A description of each parameter follows:
1098 % o clone: Specifies a pointer to a Cache structure.
1100 % o cache: the pixel cache.
1103 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1109 assert(clone != (Cache) NULL);
1110 source_info=(CacheInfo *) clone;
1111 assert(source_info->signature == MagickSignature);
1112 if (source_info->debug != MagickFalse)
1113 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1114 source_info->filename);
1115 assert(cache != (Cache) NULL);
1116 cache_info=(CacheInfo *) cache;
1117 assert(cache_info->signature == MagickSignature);
1118 source_info->methods=cache_info->methods;
1122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1126 + D e s t r o y I m a g e P i x e l C a c h e %
1130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1132 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1134 % The format of the DestroyImagePixelCache() method is:
1136 % void DestroyImagePixelCache(Image *image)
1138 % A description of each parameter follows:
1140 % o image: the image.
1143 static void DestroyImagePixelCache(Image *image)
1145 assert(image != (Image *) NULL);
1146 assert(image->signature == MagickSignature);
1147 if (image->debug != MagickFalse)
1148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1149 if (image->cache == (void *) NULL)
1151 image->cache=DestroyPixelCache(image->cache);
1155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1159 + D e s t r o y I m a g e P i x e l s %
1163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1167 % The format of the DestroyImagePixels() method is:
1169 % void DestroyImagePixels(Image *image)
1171 % A description of each parameter follows:
1173 % o image: the image.
1176 MagickExport void DestroyImagePixels(Image *image)
1181 assert(image != (const Image *) NULL);
1182 assert(image->signature == MagickSignature);
1183 if (image->debug != MagickFalse)
1184 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1185 assert(image->cache != (Cache) NULL);
1186 cache_info=(CacheInfo *) image->cache;
1187 assert(cache_info->signature == MagickSignature);
1188 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1190 cache_info->methods.destroy_pixel_handler(image);
1193 image->cache=DestroyPixelCache(image->cache);
1197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1201 + D e s t r o y P i x e l C a c h e %
1205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1207 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1209 % The format of the DestroyPixelCache() method is:
1211 % Cache DestroyPixelCache(Cache cache)
1213 % A description of each parameter follows:
1215 % o cache: the pixel cache.
1219 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1221 switch (cache_info->type)
1225 if (cache_info->mapped == MagickFalse)
1226 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
1227 cache_info->pixels);
1229 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1230 (size_t) cache_info->length);
1231 RelinquishMagickResource(MemoryResource,cache_info->length);
1236 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1237 cache_info->length);
1238 if (cache_info->mode != ReadMode)
1239 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1240 *cache_info->cache_filename='\0';
1241 RelinquishMagickResource(MapResource,cache_info->length);
1245 if (cache_info->file != -1)
1246 (void) ClosePixelCacheOnDisk(cache_info);
1247 if (cache_info->mode != ReadMode)
1248 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1249 *cache_info->cache_filename='\0';
1250 RelinquishMagickResource(DiskResource,cache_info->length);
1253 case DistributedCache:
1255 *cache_info->cache_filename='\0';
1256 (void) RelinquishDistributePixelCache(cache_info->server_info);
1262 cache_info->type=UndefinedCache;
1263 cache_info->mapped=MagickFalse;
1264 cache_info->metacontent=(void *) NULL;
1267 MagickPrivate Cache DestroyPixelCache(Cache cache)
1272 assert(cache != (Cache) NULL);
1273 cache_info=(CacheInfo *) cache;
1274 assert(cache_info->signature == MagickSignature);
1275 if (cache_info->debug != MagickFalse)
1276 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1277 cache_info->filename);
1278 LockSemaphoreInfo(cache_info->semaphore);
1279 cache_info->reference_count--;
1280 if (cache_info->reference_count != 0)
1282 UnlockSemaphoreInfo(cache_info->semaphore);
1283 return((Cache) NULL);
1285 UnlockSemaphoreInfo(cache_info->semaphore);
1286 if (cache_info->debug != MagickFalse)
1289 message[MaxTextExtent];
1291 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1292 cache_info->filename);
1293 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1295 RelinquishPixelCachePixels(cache_info);
1296 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
1297 cache_info->server_info=DestroyDistributeCacheInfo(cache_info->server_info);
1298 if (cache_info->nexus_info != (NexusInfo **) NULL)
1299 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1300 cache_info->number_threads);
1301 if (cache_info->random_info != (RandomInfo *) NULL)
1302 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1303 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
1304 DestroySemaphoreInfo(&cache_info->file_semaphore);
1305 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1306 DestroySemaphoreInfo(&cache_info->semaphore);
1307 cache_info->signature=(~MagickSignature);
1308 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1318 + D e s t r o y P i x e l C a c h e N e x u s %
1322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1326 % The format of the DestroyPixelCacheNexus() method is:
1328 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1329 % const size_t number_threads)
1331 % A description of each parameter follows:
1333 % o nexus_info: the nexus to destroy.
1335 % o number_threads: the number of nexus threads.
1339 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1341 if (nexus_info->mapped == MagickFalse)
1342 (void) RelinquishAlignedMemory(nexus_info->cache);
1344 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1345 nexus_info->cache=(Quantum *) NULL;
1346 nexus_info->pixels=(Quantum *) NULL;
1347 nexus_info->metacontent=(void *) NULL;
1348 nexus_info->length=0;
1349 nexus_info->mapped=MagickFalse;
1352 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1353 const size_t number_threads)
1358 assert(nexus_info != (NexusInfo **) NULL);
1359 for (i=0; i < (ssize_t) number_threads; i++)
1361 if (nexus_info[i]->cache != (Quantum *) NULL)
1362 RelinquishCacheNexusPixels(nexus_info[i]);
1363 nexus_info[i]->signature=(~MagickSignature);
1365 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1366 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1375 % G e t A u t h e n t i c M e t a c o n t e n t %
1379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1382 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1383 % returned if the associated pixels are not available.
1385 % The format of the GetAuthenticMetacontent() method is:
1387 % void *GetAuthenticMetacontent(const Image *image)
1389 % A description of each parameter follows:
1391 % o image: the image.
1394 MagickExport void *GetAuthenticMetacontent(const Image *image)
1400 id = GetOpenMPThreadId();
1405 assert(image != (const Image *) NULL);
1406 assert(image->signature == MagickSignature);
1407 assert(image->cache != (Cache) NULL);
1408 cache_info=(CacheInfo *) image->cache;
1409 assert(cache_info->signature == MagickSignature);
1410 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1411 (GetAuthenticMetacontentFromHandler) NULL)
1413 metacontent=cache_info->methods.
1414 get_authentic_metacontent_from_handler(image);
1415 return(metacontent);
1417 assert(id < (int) cache_info->number_threads);
1418 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1419 cache_info->nexus_info[id]);
1420 return(metacontent);
1424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428 + 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 %
1432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1434 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1435 % with the last call to QueueAuthenticPixelsCache() or
1436 % GetAuthenticPixelsCache().
1438 % The format of the GetAuthenticMetacontentFromCache() method is:
1440 % void *GetAuthenticMetacontentFromCache(const Image *image)
1442 % A description of each parameter follows:
1444 % o image: the image.
1447 static void *GetAuthenticMetacontentFromCache(const Image *image)
1453 id = GetOpenMPThreadId();
1458 assert(image != (const Image *) NULL);
1459 assert(image->signature == MagickSignature);
1460 assert(image->cache != (Cache) NULL);
1461 cache_info=(CacheInfo *) image->cache;
1462 assert(cache_info->signature == MagickSignature);
1463 assert(id < (int) cache_info->number_threads);
1464 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1465 cache_info->nexus_info[id]);
1466 return(metacontent);
1470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1474 + 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 %
1478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1481 % disk pixel cache as defined by the geometry parameters. A pointer to the
1482 % pixels is returned if the pixels are transferred, otherwise a NULL is
1485 % The format of the GetAuthenticPixelCacheNexus() method is:
1487 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1488 % const ssize_t y,const size_t columns,const size_t rows,
1489 % NexusInfo *nexus_info,ExceptionInfo *exception)
1491 % A description of each parameter follows:
1493 % o image: the image.
1495 % o x,y,columns,rows: These values define the perimeter of a region of
1498 % o nexus_info: the cache nexus to return.
1500 % o exception: return any errors or warnings in this structure.
1504 static inline MagickBooleanType IsPixelAuthentic(
1505 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1513 if (cache_info->type == PingCache)
1515 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1516 nexus_info->region.x;
1517 status=nexus_info->pixels == (cache_info->pixels+offset*
1518 cache_info->number_channels) ? MagickTrue : MagickFalse;
1522 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1523 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1524 NexusInfo *nexus_info,ExceptionInfo *exception)
1533 Transfer pixels from the cache.
1535 assert(image != (Image *) NULL);
1536 assert(image->signature == MagickSignature);
1537 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1539 if (q == (Quantum *) NULL)
1540 return((Quantum *) NULL);
1541 cache_info=(CacheInfo *) image->cache;
1542 assert(cache_info->signature == MagickSignature);
1543 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1545 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1546 return((Quantum *) NULL);
1547 if (cache_info->metacontent_extent != 0)
1548 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1549 return((Quantum *) NULL);
1554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1558 + 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 %
1562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1564 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1565 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1567 % The format of the GetAuthenticPixelsFromCache() method is:
1569 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1571 % A description of each parameter follows:
1573 % o image: the image.
1576 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1582 id = GetOpenMPThreadId();
1584 assert(image != (const Image *) NULL);
1585 assert(image->signature == MagickSignature);
1586 assert(image->cache != (Cache) NULL);
1587 cache_info=(CacheInfo *) image->cache;
1588 assert(cache_info->signature == MagickSignature);
1589 assert(id < (int) cache_info->number_threads);
1590 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598 % G e t A u t h e n t i c P i x e l Q u e u e %
1602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1604 % GetAuthenticPixelQueue() returns the authentic pixels associated
1605 % corresponding with the last call to QueueAuthenticPixels() or
1606 % GetAuthenticPixels().
1608 % The format of the GetAuthenticPixelQueue() method is:
1610 % Quantum *GetAuthenticPixelQueue(const Image image)
1612 % A description of each parameter follows:
1614 % o image: the image.
1617 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1623 id = GetOpenMPThreadId();
1625 assert(image != (const Image *) NULL);
1626 assert(image->signature == MagickSignature);
1627 assert(image->cache != (Cache) NULL);
1628 cache_info=(CacheInfo *) image->cache;
1629 assert(cache_info->signature == MagickSignature);
1630 if (cache_info->methods.get_authentic_pixels_from_handler !=
1631 (GetAuthenticPixelsFromHandler) NULL)
1632 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1633 assert(id < (int) cache_info->number_threads);
1634 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1642 % G e t A u t h e n t i c P i x e l s %
1645 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1647 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1648 % region is successfully accessed, a pointer to a Quantum array
1649 % representing the region is returned, otherwise NULL is returned.
1651 % The returned pointer may point to a temporary working copy of the pixels
1652 % or it may point to the original pixels in memory. Performance is maximized
1653 % if the selected region is part of one row, or one or more full rows, since
1654 % then there is opportunity to access the pixels in-place (without a copy)
1655 % if the image is in memory, or in a memory-mapped file. The returned pointer
1656 % must *never* be deallocated by the user.
1658 % Pixels accessed via the returned pointer represent a simple array of type
1659 % Quantum. If the image has corresponding metacontent,call
1660 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1661 % meta-content corresponding to the region. Once the Quantum array has
1662 % been updated, the changes must be saved back to the underlying image using
1663 % SyncAuthenticPixels() or they may be lost.
1665 % The format of the GetAuthenticPixels() method is:
1667 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1668 % const ssize_t y,const size_t columns,const size_t rows,
1669 % ExceptionInfo *exception)
1671 % A description of each parameter follows:
1673 % o image: the image.
1675 % o x,y,columns,rows: These values define the perimeter of a region of
1678 % o exception: return any errors or warnings in this structure.
1681 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1682 const ssize_t y,const size_t columns,const size_t rows,
1683 ExceptionInfo *exception)
1689 id = GetOpenMPThreadId();
1694 assert(image != (Image *) NULL);
1695 assert(image->signature == MagickSignature);
1696 assert(image->cache != (Cache) NULL);
1697 cache_info=(CacheInfo *) image->cache;
1698 assert(cache_info->signature == MagickSignature);
1699 if (cache_info->methods.get_authentic_pixels_handler !=
1700 (GetAuthenticPixelsHandler) NULL)
1702 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1706 assert(id < (int) cache_info->number_threads);
1707 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1708 cache_info->nexus_info[id],exception);
1713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1717 + G e t A u t h e n t i c P i x e l s C a c h e %
1721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1723 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1724 % as defined by the geometry parameters. A pointer to the pixels is returned
1725 % if the pixels are transferred, otherwise a NULL is returned.
1727 % The format of the GetAuthenticPixelsCache() method is:
1729 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1730 % const ssize_t y,const size_t columns,const size_t rows,
1731 % ExceptionInfo *exception)
1733 % A description of each parameter follows:
1735 % o image: the image.
1737 % o x,y,columns,rows: These values define the perimeter of a region of
1740 % o exception: return any errors or warnings in this structure.
1743 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1744 const ssize_t y,const size_t columns,const size_t rows,
1745 ExceptionInfo *exception)
1751 id = GetOpenMPThreadId();
1756 assert(image != (const Image *) NULL);
1757 assert(image->signature == MagickSignature);
1758 assert(image->cache != (Cache) NULL);
1759 cache_info=(CacheInfo *) image->cache;
1760 if (cache_info == (Cache) NULL)
1761 return((Quantum *) NULL);
1762 assert(cache_info->signature == MagickSignature);
1763 assert(id < (int) cache_info->number_threads);
1764 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1765 cache_info->nexus_info[id],exception);
1770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1774 + G e t I m a g e E x t e n t %
1778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1780 % GetImageExtent() returns the extent of the pixels associated corresponding
1781 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1783 % The format of the GetImageExtent() method is:
1785 % MagickSizeType GetImageExtent(const Image *image)
1787 % A description of each parameter follows:
1789 % o image: the image.
1792 MagickExport MagickSizeType GetImageExtent(const Image *image)
1798 id = GetOpenMPThreadId();
1800 assert(image != (Image *) NULL);
1801 assert(image->signature == MagickSignature);
1802 if (image->debug != MagickFalse)
1803 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1804 assert(image->cache != (Cache) NULL);
1805 cache_info=(CacheInfo *) image->cache;
1806 assert(cache_info->signature == MagickSignature);
1807 assert(id < (int) cache_info->number_threads);
1808 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1816 + G e t I m a g e P i x e l C a c h e %
1820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1822 % GetImagePixelCache() ensures that there is only a single reference to the
1823 % pixel cache to be modified, updating the provided cache pointer to point to
1824 % a clone of the original pixel cache if necessary.
1826 % The format of the GetImagePixelCache method is:
1828 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1829 % ExceptionInfo *exception)
1831 % A description of each parameter follows:
1833 % o image: the image.
1835 % o clone: any value other than MagickFalse clones the cache pixels.
1837 % o exception: return any errors or warnings in this structure.
1841 static inline MagickBooleanType ValidatePixelCacheMorphology(
1842 const Image *restrict image)
1845 *restrict cache_info;
1847 const PixelChannelMap
1852 Does the image match the pixel cache morphology?
1854 cache_info=(CacheInfo *) image->cache;
1855 p=image->channel_map;
1856 q=cache_info->channel_map;
1857 if ((image->storage_class != cache_info->storage_class) ||
1858 (image->colorspace != cache_info->colorspace) ||
1859 (image->alpha_trait != cache_info->alpha_trait) ||
1860 (image->mask != cache_info->mask) ||
1861 (image->columns != cache_info->columns) ||
1862 (image->rows != cache_info->rows) ||
1863 (image->number_channels != cache_info->number_channels) ||
1864 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1865 (image->metacontent_extent != cache_info->metacontent_extent) ||
1866 (cache_info->nexus_info == (NexusInfo **) NULL))
1867 return(MagickFalse);
1871 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1872 ExceptionInfo *exception)
1881 static MagickSizeType
1887 cache_timestamp = 0;
1890 LockSemaphoreInfo(image->semaphore);
1891 if (cpu_throttle == 0)
1897 Set CPU throttle in milleseconds.
1899 cpu_throttle=MagickResourceInfinity;
1900 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1901 if (limit == (char *) NULL)
1902 limit=GetPolicyValue("throttle");
1903 if (limit != (char *) NULL)
1905 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1906 limit=DestroyString(limit);
1909 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1910 MagickDelay(cpu_throttle);
1911 if (time_limit == 0)
1914 Set the expire time in seconds.
1916 time_limit=GetMagickResourceLimit(TimeResource);
1917 cache_timestamp=time((time_t *) NULL);
1919 if ((time_limit != MagickResourceInfinity) &&
1920 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1921 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1922 assert(image->cache != (Cache) NULL);
1923 cache_info=(CacheInfo *) image->cache;
1924 destroy=MagickFalse;
1925 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1927 LockSemaphoreInfo(cache_info->semaphore);
1928 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1939 clone_image=(*image);
1940 clone_image.semaphore=AllocateSemaphoreInfo();
1941 clone_image.reference_count=1;
1942 clone_image.cache=ClonePixelCache(cache_info);
1943 clone_info=(CacheInfo *) clone_image.cache;
1944 status=OpenPixelCache(&clone_image,IOMode,exception);
1945 if (status != MagickFalse)
1947 if (clone != MagickFalse)
1948 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1949 if (status != MagickFalse)
1951 if (cache_info->reference_count == 1)
1952 cache_info->nexus_info=(NexusInfo **) NULL;
1954 image->cache=clone_image.cache;
1957 DestroySemaphoreInfo(&clone_image.semaphore);
1959 UnlockSemaphoreInfo(cache_info->semaphore);
1961 if (destroy != MagickFalse)
1962 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1963 if (status != MagickFalse)
1966 Ensure the image matches the pixel cache morphology.
1968 image->taint=MagickTrue;
1969 image->type=UndefinedType;
1970 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1972 status=OpenPixelCache(image,IOMode,exception);
1973 cache_info=(CacheInfo *) image->cache;
1974 if (cache_info->type == DiskCache)
1975 (void) ClosePixelCacheOnDisk(cache_info);
1978 UnlockSemaphoreInfo(image->semaphore);
1979 if (status == MagickFalse)
1980 return((Cache) NULL);
1981 return(image->cache);
1985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1989 + G e t I m a g e P i x e l C a c h e T y p e %
1993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1995 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1996 % DiskCache, MemoryCache, MapCache, or PingCache.
1998 % The format of the GetImagePixelCacheType() method is:
2000 % CacheType GetImagePixelCacheType(const Image *image)
2002 % A description of each parameter follows:
2004 % o image: the image.
2007 MagickExport CacheType GetImagePixelCacheType(const Image *image)
2012 assert(image != (Image *) NULL);
2013 assert(image->signature == MagickSignature);
2014 assert(image->cache != (Cache) NULL);
2015 cache_info=(CacheInfo *) image->cache;
2016 assert(cache_info->signature == MagickSignature);
2017 return(cache_info->type);
2021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2025 % G e t O n e A u t h e n t i c P i x e l %
2029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2031 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2032 % location. The image background color is returned if an error occurs.
2034 % The format of the GetOneAuthenticPixel() method is:
2036 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2037 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2039 % A description of each parameter follows:
2041 % o image: the image.
2043 % o x,y: These values define the location of the pixel to return.
2045 % o pixel: return a pixel at the specified (x,y) location.
2047 % o exception: return any errors or warnings in this structure.
2050 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2051 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2062 assert(image != (Image *) NULL);
2063 assert(image->signature == MagickSignature);
2064 assert(image->cache != (Cache) NULL);
2065 cache_info=(CacheInfo *) image->cache;
2066 assert(cache_info->signature == MagickSignature);
2067 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2068 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2069 (GetOneAuthenticPixelFromHandler) NULL)
2070 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2072 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2073 if (q == (Quantum *) NULL)
2075 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2076 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2077 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2078 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2079 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2080 return(MagickFalse);
2082 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2087 channel=GetPixelChannelChannel(image,i);
2088 pixel[channel]=q[i];
2094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2098 + 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 %
2102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2104 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2105 % location. The image background color is returned if an error occurs.
2107 % The format of the GetOneAuthenticPixelFromCache() method is:
2109 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2110 % const ssize_t x,const ssize_t y,Quantum *pixel,
2111 % ExceptionInfo *exception)
2113 % A description of each parameter follows:
2115 % o image: the image.
2117 % o x,y: These values define the location of the pixel to return.
2119 % o pixel: return a pixel at the specified (x,y) location.
2121 % o exception: return any errors or warnings in this structure.
2124 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2125 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2131 id = GetOpenMPThreadId();
2139 assert(image != (const Image *) NULL);
2140 assert(image->signature == MagickSignature);
2141 assert(image->cache != (Cache) NULL);
2142 cache_info=(CacheInfo *) image->cache;
2143 assert(cache_info->signature == MagickSignature);
2144 assert(id < (int) cache_info->number_threads);
2145 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2146 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2148 if (q == (Quantum *) NULL)
2150 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2151 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2152 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2153 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2154 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2155 return(MagickFalse);
2157 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2162 channel=GetPixelChannelChannel(image,i);
2163 pixel[channel]=q[i];
2169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2173 % G e t O n e V i r t u a l P i x e l %
2177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2179 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2180 % (x,y) location. The image background color is returned if an error occurs.
2181 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2183 % The format of the GetOneVirtualPixel() method is:
2185 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2186 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2188 % A description of each parameter follows:
2190 % o image: the image.
2192 % o x,y: These values define the location of the pixel to return.
2194 % o pixel: return a pixel at the specified (x,y) location.
2196 % o exception: return any errors or warnings in this structure.
2199 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2200 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2206 id = GetOpenMPThreadId();
2214 assert(image != (const Image *) NULL);
2215 assert(image->signature == MagickSignature);
2216 assert(image->cache != (Cache) NULL);
2217 cache_info=(CacheInfo *) image->cache;
2218 assert(cache_info->signature == MagickSignature);
2219 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2220 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2221 (GetOneVirtualPixelFromHandler) NULL)
2222 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2223 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2224 assert(id < (int) cache_info->number_threads);
2225 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2226 1UL,1UL,cache_info->nexus_info[id],exception);
2227 if (p == (const Quantum *) NULL)
2229 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2230 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2231 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2232 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2233 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2234 return(MagickFalse);
2236 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2241 channel=GetPixelChannelChannel(image,i);
2242 pixel[channel]=p[i];
2248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2252 + 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 %
2256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2258 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2259 % specified (x,y) location. The image background color is returned if an
2262 % The format of the GetOneVirtualPixelFromCache() method is:
2264 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2265 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2266 % Quantum *pixel,ExceptionInfo *exception)
2268 % A description of each parameter follows:
2270 % o image: the image.
2272 % o virtual_pixel_method: the virtual pixel method.
2274 % o x,y: These values define the location of the pixel to return.
2276 % o pixel: return a pixel at the specified (x,y) location.
2278 % o exception: return any errors or warnings in this structure.
2281 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2282 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2283 Quantum *pixel,ExceptionInfo *exception)
2289 id = GetOpenMPThreadId();
2297 assert(image != (const Image *) NULL);
2298 assert(image->signature == MagickSignature);
2299 assert(image->cache != (Cache) NULL);
2300 cache_info=(CacheInfo *) image->cache;
2301 assert(cache_info->signature == MagickSignature);
2302 assert(id < (int) cache_info->number_threads);
2303 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2304 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2305 cache_info->nexus_info[id],exception);
2306 if (p == (const Quantum *) NULL)
2308 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2309 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2310 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2311 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2312 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2313 return(MagickFalse);
2315 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2320 channel=GetPixelChannelChannel(image,i);
2321 pixel[channel]=p[i];
2327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2331 % G e t O n e V i r t u a l P i x e l I n f o %
2335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2338 % location. The image background color is returned if an error occurs. If
2339 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2341 % The format of the GetOneVirtualPixelInfo() method is:
2343 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2344 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2345 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2347 % A description of each parameter follows:
2349 % o image: the image.
2351 % o virtual_pixel_method: the virtual pixel method.
2353 % o x,y: these values define the location of the pixel to return.
2355 % o pixel: return a pixel at the specified (x,y) location.
2357 % o exception: return any errors or warnings in this structure.
2360 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2361 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2362 PixelInfo *pixel,ExceptionInfo *exception)
2368 id = GetOpenMPThreadId();
2370 register const Quantum
2373 assert(image != (const Image *) NULL);
2374 assert(image->signature == MagickSignature);
2375 assert(image->cache != (Cache) NULL);
2376 cache_info=(CacheInfo *) image->cache;
2377 assert(cache_info->signature == MagickSignature);
2378 assert(id < (int) cache_info->number_threads);
2379 GetPixelInfo(image,pixel);
2380 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2381 cache_info->nexus_info[id],exception);
2382 if (p == (const Quantum *) NULL)
2383 return(MagickFalse);
2384 GetPixelInfoPixel(image,p,pixel);
2389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2393 + G e t P i x e l C a c h e C o l o r s p a c e %
2397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2399 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2401 % The format of the GetPixelCacheColorspace() method is:
2403 % Colorspace GetPixelCacheColorspace(Cache cache)
2405 % A description of each parameter follows:
2407 % o cache: the pixel cache.
2410 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2415 assert(cache != (Cache) NULL);
2416 cache_info=(CacheInfo *) cache;
2417 assert(cache_info->signature == MagickSignature);
2418 if (cache_info->debug != MagickFalse)
2419 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2420 cache_info->filename);
2421 return(cache_info->colorspace);
2425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2429 + G e t P i x e l C a c h e M e t h o d s %
2433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2435 % GetPixelCacheMethods() initializes the CacheMethods structure.
2437 % The format of the GetPixelCacheMethods() method is:
2439 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2441 % A description of each parameter follows:
2443 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2446 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2448 assert(cache_methods != (CacheMethods *) NULL);
2449 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2450 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2451 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2452 cache_methods->get_virtual_metacontent_from_handler=
2453 GetVirtualMetacontentFromCache;
2454 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2455 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2456 cache_methods->get_authentic_metacontent_from_handler=
2457 GetAuthenticMetacontentFromCache;
2458 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2459 cache_methods->get_one_authentic_pixel_from_handler=
2460 GetOneAuthenticPixelFromCache;
2461 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2462 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2463 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2471 + G e t P i x e l C a c h e N e x u s E x t e n t %
2475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2477 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2478 % corresponding with the last call to SetPixelCacheNexusPixels() or
2479 % GetPixelCacheNexusPixels().
2481 % The format of the GetPixelCacheNexusExtent() method is:
2483 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2484 % NexusInfo *nexus_info)
2486 % A description of each parameter follows:
2488 % o nexus_info: the nexus info.
2491 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2492 NexusInfo *nexus_info)
2500 assert(cache != NULL);
2501 cache_info=(CacheInfo *) cache;
2502 assert(cache_info->signature == MagickSignature);
2503 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2505 return((MagickSizeType) cache_info->columns*cache_info->rows);
2510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2514 + G e t P i x e l C a c h e N e x u s M e t a c o n t e n t %
2518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2520 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2523 % The format of the GetPixelCacheNexusMetacontent() method is:
2525 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2526 % NexusInfo *nexus_info)
2528 % A description of each parameter follows:
2530 % o cache: the pixel cache.
2532 % o nexus_info: the cache nexus to return the meta-content.
2535 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2536 NexusInfo *nexus_info)
2541 assert(cache != NULL);
2542 cache_info=(CacheInfo *) cache;
2543 assert(cache_info->signature == MagickSignature);
2544 if (cache_info->storage_class == UndefinedClass)
2545 return((void *) NULL);
2546 return(nexus_info->metacontent);
2550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2554 + G e t P i x e l C a c h e N e x u s P i x e l s %
2558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2560 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2563 % The format of the GetPixelCacheNexusPixels() method is:
2565 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2566 % NexusInfo *nexus_info)
2568 % A description of each parameter follows:
2570 % o cache: the pixel cache.
2572 % o nexus_info: the cache nexus to return the pixels.
2575 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2576 NexusInfo *nexus_info)
2581 assert(cache != NULL);
2582 cache_info=(CacheInfo *) cache;
2583 assert(cache_info->signature == MagickSignature);
2584 if (cache_info->storage_class == UndefinedClass)
2585 return((Quantum *) NULL);
2586 return(nexus_info->pixels);
2590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2594 + G e t P i x e l C a c h e P i x e l s %
2598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2600 % GetPixelCachePixels() returns the pixels associated with the specified image.
2602 % The format of the GetPixelCachePixels() method is:
2604 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2605 % ExceptionInfo *exception)
2607 % A description of each parameter follows:
2609 % o image: the image.
2611 % o length: the pixel cache length.
2613 % o exception: return any errors or warnings in this structure.
2616 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2617 ExceptionInfo *exception)
2622 assert(image != (const Image *) NULL);
2623 assert(image->signature == MagickSignature);
2624 assert(image->cache != (Cache) NULL);
2625 assert(length != (MagickSizeType *) NULL);
2626 assert(exception != (ExceptionInfo *) NULL);
2627 assert(exception->signature == MagickSignature);
2628 cache_info=(CacheInfo *) image->cache;
2629 assert(cache_info->signature == MagickSignature);
2631 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2632 return((void *) NULL);
2633 *length=cache_info->length;
2634 return((void *) cache_info->pixels);
2638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2642 + 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 %
2646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2648 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2650 % The format of the GetPixelCacheStorageClass() method is:
2652 % ClassType GetPixelCacheStorageClass(Cache cache)
2654 % A description of each parameter follows:
2656 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2658 % o cache: the pixel cache.
2661 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2666 assert(cache != (Cache) NULL);
2667 cache_info=(CacheInfo *) cache;
2668 assert(cache_info->signature == MagickSignature);
2669 if (cache_info->debug != MagickFalse)
2670 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2671 cache_info->filename);
2672 return(cache_info->storage_class);
2676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2680 + G e t P i x e l C a c h e T i l e S i z e %
2684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2686 % GetPixelCacheTileSize() returns the pixel cache tile size.
2688 % The format of the GetPixelCacheTileSize() method is:
2690 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2693 % A description of each parameter follows:
2695 % o image: the image.
2697 % o width: the optimize cache tile width in pixels.
2699 % o height: the optimize cache tile height in pixels.
2702 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2708 assert(image != (Image *) NULL);
2709 assert(image->signature == MagickSignature);
2710 if (image->debug != MagickFalse)
2711 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2712 cache_info=(CacheInfo *) image->cache;
2713 assert(cache_info->signature == MagickSignature);
2714 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2715 if (GetImagePixelCacheType(image) == DiskCache)
2716 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2725 + 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 %
2729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2731 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2732 % pixel cache. A virtual pixel is any pixel access that is outside the
2733 % boundaries of the image cache.
2735 % The format of the GetPixelCacheVirtualMethod() method is:
2737 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2739 % A description of each parameter follows:
2741 % o image: the image.
2744 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2749 assert(image != (Image *) NULL);
2750 assert(image->signature == MagickSignature);
2751 assert(image->cache != (Cache) NULL);
2752 cache_info=(CacheInfo *) image->cache;
2753 assert(cache_info->signature == MagickSignature);
2754 return(cache_info->virtual_pixel_method);
2758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2762 + 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 %
2766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2768 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2769 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2771 % The format of the GetVirtualMetacontentFromCache() method is:
2773 % void *GetVirtualMetacontentFromCache(const Image *image)
2775 % A description of each parameter follows:
2777 % o image: the image.
2780 static const void *GetVirtualMetacontentFromCache(const Image *image)
2786 id = GetOpenMPThreadId();
2791 assert(image != (const Image *) NULL);
2792 assert(image->signature == MagickSignature);
2793 assert(image->cache != (Cache) NULL);
2794 cache_info=(CacheInfo *) image->cache;
2795 assert(cache_info->signature == MagickSignature);
2796 assert(id < (int) cache_info->number_threads);
2797 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2798 cache_info->nexus_info[id]);
2799 return(metacontent);
2803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2807 + 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 %
2811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2813 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2816 % The format of the GetVirtualMetacontentFromNexus() method is:
2818 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2819 % NexusInfo *nexus_info)
2821 % A description of each parameter follows:
2823 % o cache: the pixel cache.
2825 % o nexus_info: the cache nexus to return the meta-content.
2828 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2829 NexusInfo *nexus_info)
2834 assert(cache != (Cache) NULL);
2835 cache_info=(CacheInfo *) cache;
2836 assert(cache_info->signature == MagickSignature);
2837 if (cache_info->storage_class == UndefinedClass)
2838 return((void *) NULL);
2839 return(nexus_info->metacontent);
2843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847 % G e t V i r t u a l M e t a c o n t e n t %
2851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2853 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2854 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2855 % returned if the meta-content are not available.
2857 % The format of the GetVirtualMetacontent() method is:
2859 % const void *GetVirtualMetacontent(const Image *image)
2861 % A description of each parameter follows:
2863 % o image: the image.
2866 MagickExport const void *GetVirtualMetacontent(const Image *image)
2872 id = GetOpenMPThreadId();
2877 assert(image != (const Image *) NULL);
2878 assert(image->signature == MagickSignature);
2879 assert(image->cache != (Cache) NULL);
2880 cache_info=(CacheInfo *) image->cache;
2881 assert(cache_info->signature == MagickSignature);
2882 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2883 if (metacontent != (void *) NULL)
2884 return(metacontent);
2885 assert(id < (int) cache_info->number_threads);
2886 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2887 cache_info->nexus_info[id]);
2888 return(metacontent);
2892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2896 + 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 %
2900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2902 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2903 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2904 % is returned if the pixels are transferred, otherwise a NULL is returned.
2906 % The format of the GetVirtualPixelsFromNexus() method is:
2908 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2909 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2910 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2911 % ExceptionInfo *exception)
2913 % A description of each parameter follows:
2915 % o image: the image.
2917 % o virtual_pixel_method: the virtual pixel method.
2919 % o x,y,columns,rows: These values define the perimeter of a region of
2922 % o nexus_info: the cache nexus to acquire.
2924 % o exception: return any errors or warnings in this structure.
2931 0, 48, 12, 60, 3, 51, 15, 63,
2932 32, 16, 44, 28, 35, 19, 47, 31,
2933 8, 56, 4, 52, 11, 59, 7, 55,
2934 40, 24, 36, 20, 43, 27, 39, 23,
2935 2, 50, 14, 62, 1, 49, 13, 61,
2936 34, 18, 46, 30, 33, 17, 45, 29,
2937 10, 58, 6, 54, 9, 57, 5, 53,
2938 42, 26, 38, 22, 41, 25, 37, 21
2941 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2946 index=x+DitherMatrix[x & 0x07]-32L;
2949 if (index >= (ssize_t) columns)
2950 return((ssize_t) columns-1L);
2954 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2959 index=y+DitherMatrix[y & 0x07]-32L;
2962 if (index >= (ssize_t) rows)
2963 return((ssize_t) rows-1L);
2967 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2971 if (x >= (ssize_t) columns)
2972 return((ssize_t) (columns-1));
2976 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2980 if (y >= (ssize_t) rows)
2981 return((ssize_t) (rows-1));
2985 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2987 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2990 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2992 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2995 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2996 const size_t extent)
3002 Compute the remainder of dividing offset by extent. It returns not only
3003 the quotient (tile the offset falls in) but also the positive remainer
3004 within that tile such that 0 <= remainder < extent. This method is
3005 essentially a ldiv() using a floored modulo division rather than the
3006 normal default truncated modulo division.
3008 modulo.quotient=offset/(ssize_t) extent;
3011 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3015 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3016 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3017 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3018 ExceptionInfo *exception)
3035 virtual_pixel[CompositePixelChannel];
3040 register const Quantum
3053 register unsigned char
3060 *virtual_metacontent;
3065 assert(image != (const Image *) NULL);
3066 assert(image->signature == MagickSignature);
3067 assert(image->cache != (Cache) NULL);
3068 cache_info=(CacheInfo *) image->cache;
3069 assert(cache_info->signature == MagickSignature);
3070 if (cache_info->type == UndefinedCache)
3071 return((const Quantum *) NULL);
3074 region.width=columns;
3076 pixels=SetPixelCacheNexusPixels(image,ReadMode,®ion,nexus_info,exception);
3077 if (pixels == (Quantum *) NULL)
3078 return((const Quantum *) NULL);
3080 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3081 nexus_info->region.x;
3082 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3083 nexus_info->region.width-1L;
3084 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3085 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3086 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3087 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3093 Pixel request is inside cache extents.
3095 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3097 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3098 if (status == MagickFalse)
3099 return((const Quantum *) NULL);
3100 if (cache_info->metacontent_extent != 0)
3102 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3103 if (status == MagickFalse)
3104 return((const Quantum *) NULL);
3109 Pixel request is outside cache extents.
3111 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3112 virtual_nexus=AcquirePixelCacheNexus(1);
3113 if (virtual_nexus == (NexusInfo **) NULL)
3115 if (virtual_nexus != (NexusInfo **) NULL)
3116 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3117 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3118 "UnableToGetCacheNexus","`%s'",image->filename);
3119 return((const Quantum *) NULL);
3121 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3122 sizeof(*virtual_pixel));
3123 virtual_metacontent=(void *) NULL;
3124 switch (virtual_pixel_method)
3126 case BackgroundVirtualPixelMethod:
3127 case BlackVirtualPixelMethod:
3128 case GrayVirtualPixelMethod:
3129 case TransparentVirtualPixelMethod:
3130 case MaskVirtualPixelMethod:
3131 case WhiteVirtualPixelMethod:
3132 case EdgeVirtualPixelMethod:
3133 case CheckerTileVirtualPixelMethod:
3134 case HorizontalTileVirtualPixelMethod:
3135 case VerticalTileVirtualPixelMethod:
3137 if (cache_info->metacontent_extent != 0)
3140 Acquire a metacontent buffer.
3142 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3143 cache_info->metacontent_extent);
3144 if (virtual_metacontent == (void *) NULL)
3146 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3147 (void) ThrowMagickException(exception,GetMagickModule(),
3148 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3149 return((const Quantum *) NULL);
3151 (void) ResetMagickMemory(virtual_metacontent,0,
3152 cache_info->metacontent_extent);
3154 switch (virtual_pixel_method)
3156 case BlackVirtualPixelMethod:
3158 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3159 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3160 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3163 case GrayVirtualPixelMethod:
3165 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3166 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3168 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3171 case TransparentVirtualPixelMethod:
3173 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3174 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3175 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3178 case MaskVirtualPixelMethod:
3179 case WhiteVirtualPixelMethod:
3181 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3182 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3183 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3188 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3190 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3192 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3194 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3196 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3206 for (v=0; v < (ssize_t) rows; v++)
3208 for (u=0; u < (ssize_t) columns; u+=length)
3210 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3211 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3212 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3220 Transfer a single pixel.
3222 length=(MagickSizeType) 1;
3223 switch (virtual_pixel_method)
3227 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3228 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3229 1UL,1UL,*virtual_nexus,exception);
3230 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3233 case RandomVirtualPixelMethod:
3235 if (cache_info->random_info == (RandomInfo *) NULL)
3236 cache_info->random_info=AcquireRandomInfo();
3237 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3238 RandomX(cache_info->random_info,cache_info->columns),
3239 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3240 *virtual_nexus,exception);
3241 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3244 case DitherVirtualPixelMethod:
3246 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3247 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3248 1UL,1UL,*virtual_nexus,exception);
3249 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3252 case TileVirtualPixelMethod:
3254 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3255 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3256 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3257 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3259 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3262 case MirrorVirtualPixelMethod:
3264 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3265 if ((x_modulo.quotient & 0x01) == 1L)
3266 x_modulo.remainder=(ssize_t) cache_info->columns-
3267 x_modulo.remainder-1L;
3268 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3269 if ((y_modulo.quotient & 0x01) == 1L)
3270 y_modulo.remainder=(ssize_t) cache_info->rows-
3271 y_modulo.remainder-1L;
3272 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3273 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3275 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3278 case HorizontalTileEdgeVirtualPixelMethod:
3280 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3281 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3282 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3283 *virtual_nexus,exception);
3284 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3287 case VerticalTileEdgeVirtualPixelMethod:
3289 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3290 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3291 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3292 *virtual_nexus,exception);
3293 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3296 case BackgroundVirtualPixelMethod:
3297 case BlackVirtualPixelMethod:
3298 case GrayVirtualPixelMethod:
3299 case TransparentVirtualPixelMethod:
3300 case MaskVirtualPixelMethod:
3301 case WhiteVirtualPixelMethod:
3304 r=virtual_metacontent;
3307 case EdgeVirtualPixelMethod:
3308 case CheckerTileVirtualPixelMethod:
3310 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3311 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3312 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3315 r=virtual_metacontent;
3318 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3319 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3321 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3324 case HorizontalTileVirtualPixelMethod:
3326 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3329 r=virtual_metacontent;
3332 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3333 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3334 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3335 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3337 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3340 case VerticalTileVirtualPixelMethod:
3342 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3345 r=virtual_metacontent;
3348 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3349 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3350 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3351 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3353 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3357 if (p == (const Quantum *) NULL)
3359 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3361 q+=cache_info->number_channels;
3362 if ((s != (void *) NULL) && (r != (const void *) NULL))
3364 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3365 s+=cache_info->metacontent_extent;
3370 Transfer a run of pixels.
3372 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3373 length,1UL,*virtual_nexus,exception);
3374 if (p == (const Quantum *) NULL)
3376 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3377 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3378 q+=length*cache_info->number_channels;
3379 if ((r != (void *) NULL) && (s != (const void *) NULL))
3381 (void) memcpy(s,r,(size_t) length);
3382 s+=length*cache_info->metacontent_extent;
3389 if (virtual_metacontent != (void *) NULL)
3390 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3391 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3400 + G e t V i r t u a l P i x e l C a c h e %
3404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3406 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3407 % cache as defined by the geometry parameters. A pointer to the pixels
3408 % is returned if the pixels are transferred, otherwise a NULL is returned.
3410 % The format of the GetVirtualPixelCache() method is:
3412 % const Quantum *GetVirtualPixelCache(const Image *image,
3413 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3414 % const ssize_t y,const size_t columns,const size_t rows,
3415 % ExceptionInfo *exception)
3417 % A description of each parameter follows:
3419 % o image: the image.
3421 % o virtual_pixel_method: the virtual pixel method.
3423 % o x,y,columns,rows: These values define the perimeter of a region of
3426 % o exception: return any errors or warnings in this structure.
3429 static const Quantum *GetVirtualPixelCache(const Image *image,
3430 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3431 const size_t columns,const size_t rows,ExceptionInfo *exception)
3437 id = GetOpenMPThreadId();
3442 assert(image != (const Image *) NULL);
3443 assert(image->signature == MagickSignature);
3444 assert(image->cache != (Cache) NULL);
3445 cache_info=(CacheInfo *) image->cache;
3446 assert(cache_info->signature == MagickSignature);
3447 assert(id < (int) cache_info->number_threads);
3448 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3449 cache_info->nexus_info[id],exception);
3454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3458 % G e t V i r t u a l P i x e l Q u e u e %
3462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3464 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3465 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3467 % The format of the GetVirtualPixelQueue() method is:
3469 % const Quantum *GetVirtualPixelQueue(const Image image)
3471 % A description of each parameter follows:
3473 % o image: the image.
3476 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3482 id = GetOpenMPThreadId();
3484 assert(image != (const Image *) NULL);
3485 assert(image->signature == MagickSignature);
3486 assert(image->cache != (Cache) NULL);
3487 cache_info=(CacheInfo *) image->cache;
3488 assert(cache_info->signature == MagickSignature);
3489 if (cache_info->methods.get_virtual_pixels_handler !=
3490 (GetVirtualPixelsHandler) NULL)
3491 return(cache_info->methods.get_virtual_pixels_handler(image));
3492 assert(id < (int) cache_info->number_threads);
3493 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3501 % G e t V i r t u a l P i x e l s %
3505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3507 % GetVirtualPixels() returns an immutable pixel region. If the
3508 % region is successfully accessed, a pointer to it is returned, otherwise
3509 % NULL is returned. The returned pointer may point to a temporary working
3510 % copy of the pixels or it may point to the original pixels in memory.
3511 % Performance is maximized if the selected region is part of one row, or one
3512 % or more full rows, since there is opportunity to access the pixels in-place
3513 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3514 % returned pointer must *never* be deallocated by the user.
3516 % Pixels accessed via the returned pointer represent a simple array of type
3517 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3518 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3519 % access the meta-content (of type void) corresponding to the the
3522 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3524 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3525 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3526 % GetCacheViewAuthenticPixels() instead.
3528 % The format of the GetVirtualPixels() method is:
3530 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3531 % const ssize_t y,const size_t columns,const size_t rows,
3532 % ExceptionInfo *exception)
3534 % A description of each parameter follows:
3536 % o image: the image.
3538 % o x,y,columns,rows: These values define the perimeter of a region of
3541 % o exception: return any errors or warnings in this structure.
3544 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3545 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3546 ExceptionInfo *exception)
3552 id = GetOpenMPThreadId();
3557 assert(image != (const Image *) NULL);
3558 assert(image->signature == MagickSignature);
3559 assert(image->cache != (Cache) NULL);
3560 cache_info=(CacheInfo *) image->cache;
3561 assert(cache_info->signature == MagickSignature);
3562 if (cache_info->methods.get_virtual_pixel_handler !=
3563 (GetVirtualPixelHandler) NULL)
3564 return(cache_info->methods.get_virtual_pixel_handler(image,
3565 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3566 assert(id < (int) cache_info->number_threads);
3567 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3568 columns,rows,cache_info->nexus_info[id],exception);
3573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3577 + 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 %
3581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3583 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3584 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3586 % The format of the GetVirtualPixelsCache() method is:
3588 % Quantum *GetVirtualPixelsCache(const Image *image)
3590 % A description of each parameter follows:
3592 % o image: the image.
3595 static const Quantum *GetVirtualPixelsCache(const Image *image)
3601 id = GetOpenMPThreadId();
3603 assert(image != (const Image *) NULL);
3604 assert(image->signature == MagickSignature);
3605 assert(image->cache != (Cache) NULL);
3606 cache_info=(CacheInfo *) image->cache;
3607 assert(cache_info->signature == MagickSignature);
3608 assert(id < (int) cache_info->number_threads);
3609 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3617 + G e t V i r t u a l P i x e l s N e x u s %
3621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3623 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3626 % The format of the GetVirtualPixelsNexus() method is:
3628 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3629 % NexusInfo *nexus_info)
3631 % A description of each parameter follows:
3633 % o cache: the pixel cache.
3635 % o nexus_info: the cache nexus to return the colormap pixels.
3638 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3639 NexusInfo *nexus_info)
3644 assert(cache != (Cache) NULL);
3645 cache_info=(CacheInfo *) cache;
3646 assert(cache_info->signature == MagickSignature);
3647 if (cache_info->storage_class == UndefinedClass)
3648 return((Quantum *) NULL);
3649 return((const Quantum *) nexus_info->pixels);
3653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3657 + O p e n P i x e l C a c h e %
3661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3663 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3664 % dimensions, allocating space for the image pixels and optionally the
3665 % metacontent, and memory mapping the cache if it is disk based. The cache
3666 % nexus array is initialized as well.
3668 % The format of the OpenPixelCache() method is:
3670 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3671 % ExceptionInfo *exception)
3673 % A description of each parameter follows:
3675 % o image: the image.
3677 % o mode: ReadMode, WriteMode, or IOMode.
3679 % o exception: return any errors or warnings in this structure.
3683 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3685 cache_info->mapped=MagickFalse;
3686 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3687 (size_t) cache_info->length));
3688 if (cache_info->pixels == (Quantum *) NULL)
3690 cache_info->mapped=MagickTrue;
3691 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3692 cache_info->length);
3696 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3706 cache_info=(CacheInfo *) image->cache;
3707 if (image->debug != MagickFalse)
3710 format[MaxTextExtent],
3711 message[MaxTextExtent];
3713 (void) FormatMagickSize(length,MagickFalse,format);
3714 (void) FormatLocaleString(message,MaxTextExtent,
3715 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3716 cache_info->cache_filename,cache_info->file,format);
3717 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3719 if (length != (MagickSizeType) ((MagickOffsetType) length))
3720 return(MagickFalse);
3721 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3723 return(MagickFalse);
3724 if ((MagickSizeType) offset >= length)
3726 extent=(MagickOffsetType) length-1;
3727 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3728 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3729 if (cache_info->synchronize != MagickFalse)
3734 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3736 return(MagickFalse);
3739 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3742 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3743 ExceptionInfo *exception)
3750 format[MaxTextExtent],
3751 message[MaxTextExtent];
3767 assert(image != (const Image *) NULL);
3768 assert(image->signature == MagickSignature);
3769 assert(image->cache != (Cache) NULL);
3770 if (image->debug != MagickFalse)
3771 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3772 if ((image->columns == 0) || (image->rows == 0))
3773 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3774 cache_info=(CacheInfo *) image->cache;
3775 assert(cache_info->signature == MagickSignature);
3776 source_info=(*cache_info);
3777 source_info.file=(-1);
3778 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3779 image->filename,(double) GetImageIndexInList(image));
3780 cache_info->storage_class=image->storage_class;
3781 cache_info->colorspace=image->colorspace;
3782 cache_info->alpha_trait=image->alpha_trait;
3783 cache_info->mask=image->mask;
3784 cache_info->rows=image->rows;
3785 cache_info->columns=image->columns;
3786 InitializePixelChannelMap(image);
3787 cache_info->number_channels=GetPixelChannels(image);
3788 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3789 sizeof(*image->channel_map));
3790 cache_info->metacontent_extent=image->metacontent_extent;
3791 cache_info->mode=mode;
3792 if (image->ping != MagickFalse)
3794 cache_info->type=PingCache;
3795 cache_info->pixels=(Quantum *) NULL;
3796 cache_info->metacontent=(void *) NULL;
3797 cache_info->length=0;
3800 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3801 packet_size=cache_info->number_channels*sizeof(Quantum);
3802 if (image->metacontent_extent != 0)
3803 packet_size+=cache_info->metacontent_extent;
3804 length=number_pixels*packet_size;
3805 columns=(size_t) (length/cache_info->rows/packet_size);
3806 if (cache_info->columns != columns)
3807 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3809 cache_info->length=length;
3810 status=AcquireMagickResource(AreaResource,cache_info->length);
3811 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3812 cache_info->metacontent_extent);
3813 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3815 status=AcquireMagickResource(MemoryResource,cache_info->length);
3816 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3817 (cache_info->type == MemoryCache))
3819 AllocatePixelCachePixels(cache_info);
3820 if (cache_info->pixels == (Quantum *) NULL)
3821 cache_info->pixels=source_info.pixels;
3825 Create memory pixel cache.
3828 cache_info->type=MemoryCache;
3829 cache_info->metacontent=(void *) NULL;
3830 if (cache_info->metacontent_extent != 0)
3831 cache_info->metacontent=(void *) (cache_info->pixels+
3832 number_pixels*cache_info->number_channels);
3833 if ((source_info.storage_class != UndefinedClass) &&
3836 status=ClonePixelCachePixels(cache_info,&source_info,
3838 RelinquishPixelCachePixels(&source_info);
3840 if (image->debug != MagickFalse)
3842 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3843 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3845 (void) FormatLocaleString(message,MaxTextExtent,
3846 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3847 cache_info->filename,cache_info->mapped != MagickFalse ?
3848 "Anonymous" : "Heap",type,(double) cache_info->columns,
3849 (double) cache_info->rows,(double)
3850 cache_info->number_channels,format);
3851 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3857 RelinquishMagickResource(MemoryResource,cache_info->length);
3860 Create pixel cache on disk.
3862 status=AcquireMagickResource(DiskResource,cache_info->length);
3863 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3868 if (cache_info->type == DistributedCache)
3869 RelinquishMagickResource(DiskResource,cache_info->length);
3870 server_info=AcquireDistributeCacheInfo(exception);
3871 if (server_info != (DistributeCacheInfo *) NULL)
3873 status=OpenDistributePixelCache(server_info,image);
3874 if (status == MagickFalse)
3875 server_info=DestroyDistributeCacheInfo(server_info);
3879 Create a distributed pixel cache.
3881 cache_info->type=DistributedCache;
3882 cache_info->server_info=server_info;
3883 (void) FormatLocaleString(cache_info->cache_filename,
3884 MaxTextExtent,"%s:%d",
3885 GetDistributeCacheHostname(cache_info->server_info),
3886 GetDistributeCachePort(cache_info->server_info));
3887 if ((source_info.storage_class != UndefinedClass) &&
3890 status=ClonePixelCachePixels(cache_info,&source_info,
3892 RelinquishPixelCachePixels(&source_info);
3894 if (image->debug != MagickFalse)
3896 (void) FormatMagickSize(cache_info->length,MagickFalse,
3898 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3900 (void) FormatLocaleString(message,MaxTextExtent,
3901 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3902 cache_info->filename,cache_info->cache_filename,
3903 GetDistributeCacheFile(cache_info->server_info),type,
3904 (double) cache_info->columns,(double) cache_info->rows,
3905 (double) cache_info->number_channels,format);
3906 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3912 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3913 "CacheResourcesExhausted","`%s'",image->filename);
3914 return(MagickFalse);
3916 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3918 (void) ClosePixelCacheOnDisk(cache_info);
3919 *cache_info->cache_filename='\0';
3921 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3923 RelinquishMagickResource(DiskResource,cache_info->length);
3924 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3926 return(MagickFalse);
3928 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3929 cache_info->length);
3930 if (status == MagickFalse)
3932 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3934 return(MagickFalse);
3936 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3937 cache_info->metacontent_extent);
3938 if (length != (MagickSizeType) ((size_t) length))
3939 cache_info->type=DiskCache;
3942 status=AcquireMagickResource(MapResource,cache_info->length);
3943 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3944 (cache_info->type != MemoryCache))
3945 cache_info->type=DiskCache;
3948 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3949 cache_info->offset,(size_t) cache_info->length);
3950 if (cache_info->pixels == (Quantum *) NULL)
3952 cache_info->type=DiskCache;
3953 cache_info->pixels=source_info.pixels;
3958 Create file-backed memory-mapped pixel cache.
3961 (void) ClosePixelCacheOnDisk(cache_info);
3962 cache_info->type=MapCache;
3963 cache_info->mapped=MagickTrue;
3964 cache_info->metacontent=(void *) NULL;
3965 if (cache_info->metacontent_extent != 0)
3966 cache_info->metacontent=(void *) (cache_info->pixels+
3967 number_pixels*cache_info->number_channels);
3968 if ((source_info.storage_class != UndefinedClass) &&
3971 status=ClonePixelCachePixels(cache_info,&source_info,
3973 RelinquishPixelCachePixels(&source_info);
3975 if (image->debug != MagickFalse)
3977 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3978 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3980 (void) FormatLocaleString(message,MaxTextExtent,
3981 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3982 cache_info->filename,cache_info->cache_filename,
3983 cache_info->file,type,(double) cache_info->columns,(double)
3984 cache_info->rows,(double) cache_info->number_channels,
3986 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3992 RelinquishMagickResource(MapResource,cache_info->length);
3995 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3997 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3998 RelinquishPixelCachePixels(&source_info);
4000 if (image->debug != MagickFalse)
4002 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4003 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4005 (void) FormatLocaleString(message,MaxTextExtent,
4006 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
4007 cache_info->cache_filename,cache_info->file,type,(double)
4008 cache_info->columns,(double) cache_info->rows,(double)
4009 cache_info->number_channels,format);
4010 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4016 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4020 + P e r s i s t P i x e l C a c h e %
4024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4026 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4027 % persistent pixel cache is one that resides on disk and is not destroyed
4028 % when the program exits.
4030 % The format of the PersistPixelCache() method is:
4032 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4033 % const MagickBooleanType attach,MagickOffsetType *offset,
4034 % ExceptionInfo *exception)
4036 % A description of each parameter follows:
4038 % o image: the image.
4040 % o filename: the persistent pixel cache filename.
4042 % o attach: A value other than zero initializes the persistent pixel cache.
4044 % o initialize: A value other than zero initializes the persistent pixel
4047 % o offset: the offset in the persistent cache to store pixels.
4049 % o exception: return any errors or warnings in this structure.
4052 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4053 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4054 ExceptionInfo *exception)
4069 assert(image != (Image *) NULL);
4070 assert(image->signature == MagickSignature);
4071 if (image->debug != MagickFalse)
4072 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4073 assert(image->cache != (void *) NULL);
4074 assert(filename != (const char *) NULL);
4075 assert(offset != (MagickOffsetType *) NULL);
4076 page_size=GetMagickPageSize();
4077 cache_info=(CacheInfo *) image->cache;
4078 assert(cache_info->signature == MagickSignature);
4079 if (attach != MagickFalse)
4082 Attach existing persistent pixel cache.
4084 if (image->debug != MagickFalse)
4085 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4086 "attach persistent cache");
4087 (void) CopyMagickString(cache_info->cache_filename,filename,
4089 cache_info->type=DiskCache;
4090 cache_info->offset=(*offset);
4091 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4092 return(MagickFalse);
4093 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4096 if ((cache_info->mode != ReadMode) &&
4097 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
4098 (cache_info->reference_count == 1))
4100 LockSemaphoreInfo(cache_info->semaphore);
4101 if ((cache_info->mode != ReadMode) &&
4102 ((cache_info->type == DiskCache) || (cache_info->type == MapCache)) &&
4103 (cache_info->reference_count == 1))
4109 Usurp existing persistent pixel cache.
4111 status=rename_utf8(cache_info->cache_filename,filename);
4114 (void) CopyMagickString(cache_info->cache_filename,filename,
4116 *offset+=cache_info->length+page_size-(cache_info->length %
4118 UnlockSemaphoreInfo(cache_info->semaphore);
4119 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4120 if (image->debug != MagickFalse)
4121 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4122 "Usurp resident persistent cache");
4126 UnlockSemaphoreInfo(cache_info->semaphore);
4129 Clone persistent pixel cache.
4131 clone_image=(*image);
4132 clone_info=(CacheInfo *) clone_image.cache;
4133 image->cache=ClonePixelCache(cache_info);
4134 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4135 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4136 cache_info->type=DiskCache;
4137 cache_info->offset=(*offset);
4138 cache_info=(CacheInfo *) image->cache;
4139 status=OpenPixelCache(image,IOMode,exception);
4140 if (status != MagickFalse)
4141 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4142 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4143 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4152 + 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 %
4156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4158 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4159 % defined by the region rectangle and returns a pointer to the region. This
4160 % region is subsequently transferred from the pixel cache with
4161 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4162 % pixels are transferred, otherwise a NULL is returned.
4164 % The format of the QueueAuthenticPixelCacheNexus() method is:
4166 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4167 % const ssize_t y,const size_t columns,const size_t rows,
4168 % const MagickBooleanType clone,NexusInfo *nexus_info,
4169 % ExceptionInfo *exception)
4171 % A description of each parameter follows:
4173 % o image: the image.
4175 % o x,y,columns,rows: These values define the perimeter of a region of
4178 % o nexus_info: the cache nexus to set.
4180 % o clone: clone the pixel cache.
4182 % o exception: return any errors or warnings in this structure.
4185 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4186 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4187 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4202 Validate pixel cache geometry.
4204 assert(image != (const Image *) NULL);
4205 assert(image->signature == MagickSignature);
4206 assert(image->cache != (Cache) NULL);
4207 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4208 if (cache_info == (Cache) NULL)
4209 return((Quantum *) NULL);
4210 assert(cache_info->signature == MagickSignature);
4211 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4213 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4214 "NoPixelsDefinedInCache","`%s'",image->filename);
4215 return((Quantum *) NULL);
4217 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4218 (y >= (ssize_t) cache_info->rows))
4220 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4221 "PixelsAreNotAuthentic","`%s'",image->filename);
4222 return((Quantum *) NULL);
4224 offset=(MagickOffsetType) y*cache_info->columns+x;
4226 return((Quantum *) NULL);
4227 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4228 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4229 if ((MagickSizeType) offset >= number_pixels)
4230 return((Quantum *) NULL);
4236 region.width=columns;
4238 return(SetPixelCacheNexusPixels(image,WriteMode,®ion,nexus_info,exception));
4242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4246 + 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 %
4250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4252 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4253 % defined by the region rectangle and returns a pointer to the region. This
4254 % region is subsequently transferred from the pixel cache with
4255 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4256 % pixels are transferred, otherwise a NULL is returned.
4258 % The format of the QueueAuthenticPixelsCache() method is:
4260 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4261 % const ssize_t y,const size_t columns,const size_t rows,
4262 % ExceptionInfo *exception)
4264 % A description of each parameter follows:
4266 % o image: the image.
4268 % o x,y,columns,rows: These values define the perimeter of a region of
4271 % o exception: return any errors or warnings in this structure.
4274 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4275 const ssize_t y,const size_t columns,const size_t rows,
4276 ExceptionInfo *exception)
4282 id = GetOpenMPThreadId();
4287 assert(image != (const Image *) NULL);
4288 assert(image->signature == MagickSignature);
4289 assert(image->cache != (Cache) NULL);
4290 cache_info=(CacheInfo *) image->cache;
4291 assert(cache_info->signature == MagickSignature);
4292 assert(id < (int) cache_info->number_threads);
4293 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4294 cache_info->nexus_info[id],exception);
4299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4303 % Q u e u e A u t h e n t i c P i x e l s %
4307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4309 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4310 % successfully initialized a pointer to a Quantum array representing the
4311 % region is returned, otherwise NULL is returned. The returned pointer may
4312 % point to a temporary working buffer for the pixels or it may point to the
4313 % final location of the pixels in memory.
4315 % Write-only access means that any existing pixel values corresponding to
4316 % the region are ignored. This is useful if the initial image is being
4317 % created from scratch, or if the existing pixel values are to be
4318 % completely replaced without need to refer to their pre-existing values.
4319 % The application is free to read and write the pixel buffer returned by
4320 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4321 % initialize the pixel array values. Initializing pixel array values is the
4322 % application's responsibility.
4324 % Performance is maximized if the selected region is part of one row, or
4325 % one or more full rows, since then there is opportunity to access the
4326 % pixels in-place (without a copy) if the image is in memory, or in a
4327 % memory-mapped file. The returned pointer must *never* be deallocated
4330 % Pixels accessed via the returned pointer represent a simple array of type
4331 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4332 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4333 % obtain the meta-content (of type void) corresponding to the region.
4334 % Once the Quantum (and/or Quantum) array has been updated, the
4335 % changes must be saved back to the underlying image using
4336 % SyncAuthenticPixels() or they may be lost.
4338 % The format of the QueueAuthenticPixels() method is:
4340 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4341 % const ssize_t y,const size_t columns,const size_t rows,
4342 % ExceptionInfo *exception)
4344 % A description of each parameter follows:
4346 % o image: the image.
4348 % o x,y,columns,rows: These values define the perimeter of a region of
4351 % o exception: return any errors or warnings in this structure.
4354 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4355 const ssize_t y,const size_t columns,const size_t rows,
4356 ExceptionInfo *exception)
4362 id = GetOpenMPThreadId();
4367 assert(image != (Image *) NULL);
4368 assert(image->signature == MagickSignature);
4369 assert(image->cache != (Cache) NULL);
4370 cache_info=(CacheInfo *) image->cache;
4371 assert(cache_info->signature == MagickSignature);
4372 if (cache_info->methods.queue_authentic_pixels_handler !=
4373 (QueueAuthenticPixelsHandler) NULL)
4375 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4379 assert(id < (int) cache_info->number_threads);
4380 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4381 cache_info->nexus_info[id],exception);
4386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4390 + 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 %
4394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4396 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4399 % The format of the ReadPixelCacheMetacontent() method is:
4401 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4402 % NexusInfo *nexus_info,ExceptionInfo *exception)
4404 % A description of each parameter follows:
4406 % o cache_info: the pixel cache.
4408 % o nexus_info: the cache nexus to read the metacontent.
4410 % o exception: return any errors or warnings in this structure.
4413 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4414 NexusInfo *nexus_info,ExceptionInfo *exception)
4430 register unsigned char
4433 if (cache_info->metacontent_extent == 0)
4434 return(MagickFalse);
4435 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4437 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4438 nexus_info->region.x;
4439 length=(MagickSizeType) nexus_info->region.width*
4440 cache_info->metacontent_extent;
4441 extent=length*nexus_info->region.height;
4442 region=nexus_info->region;
4444 q=(unsigned char *) nexus_info->metacontent;
4445 switch (cache_info->type)
4450 register unsigned char
4454 Read meta-content from memory.
4456 if ((cache_info->columns == nexus_info->region.width) &&
4457 (extent == (MagickSizeType) ((size_t) extent)))
4462 p=(unsigned char *) cache_info->metacontent+offset*
4463 cache_info->metacontent_extent;
4464 for (y=0; y < (ssize_t) region.height; y++)
4466 (void) memcpy(q,p,(size_t) length);
4467 p+=cache_info->metacontent_extent*cache_info->columns;
4468 q+=cache_info->metacontent_extent*nexus_info->region.width;
4475 Read meta content from disk.
4477 LockSemaphoreInfo(cache_info->file_semaphore);
4478 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4480 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4481 cache_info->cache_filename);
4482 UnlockSemaphoreInfo(cache_info->file_semaphore);
4483 return(MagickFalse);
4485 if ((cache_info->columns == nexus_info->region.width) &&
4486 (extent <= MagickMaxBufferExtent))
4491 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4492 for (y=0; y < (ssize_t) region.height; y++)
4494 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4495 cache_info->number_channels*sizeof(Quantum)+offset*
4496 cache_info->metacontent_extent,length,(unsigned char *) q);
4497 if (count != (MagickOffsetType) length)
4499 offset+=cache_info->columns;
4500 q+=cache_info->metacontent_extent*nexus_info->region.width;
4502 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4503 (void) ClosePixelCacheOnDisk(cache_info);
4504 UnlockSemaphoreInfo(cache_info->file_semaphore);
4507 case DistributedCache:
4510 Read metacontent from distributed cache.
4512 LockSemaphoreInfo(cache_info->file_semaphore);
4514 for (y=0; y < (ssize_t) region.height; y++)
4516 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4517 length,(unsigned char *) q);
4518 if (count != (MagickOffsetType) length)
4520 q+=cache_info->metacontent_extent*nexus_info->region.width;
4523 UnlockSemaphoreInfo(cache_info->file_semaphore);
4529 if (y < (ssize_t) region.height)
4531 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4532 cache_info->cache_filename);
4533 return(MagickFalse);
4535 if ((cache_info->debug != MagickFalse) &&
4536 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4537 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4538 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4539 nexus_info->region.width,(double) nexus_info->region.height,(double)
4540 nexus_info->region.x,(double) nexus_info->region.y);
4545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4549 + R e a d P i x e l C a c h e P i x e l s %
4553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4555 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4558 % The format of the ReadPixelCachePixels() method is:
4560 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4561 % NexusInfo *nexus_info,ExceptionInfo *exception)
4563 % A description of each parameter follows:
4565 % o cache_info: the pixel cache.
4567 % o nexus_info: the cache nexus to read the pixels.
4569 % o exception: return any errors or warnings in this structure.
4572 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4573 NexusInfo *nexus_info,ExceptionInfo *exception)
4592 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4594 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4595 nexus_info->region.x;
4596 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4598 extent=length*nexus_info->region.height;
4599 region=nexus_info->region;
4601 q=nexus_info->pixels;
4602 switch (cache_info->type)
4611 Read pixels from memory.
4613 if ((cache_info->columns == nexus_info->region.width) &&
4614 (extent == (MagickSizeType) ((size_t) extent)))
4619 p=cache_info->pixels+offset*cache_info->number_channels;
4620 for (y=0; y < (ssize_t) region.height; y++)
4622 (void) memcpy(q,p,(size_t) length);
4623 p+=cache_info->number_channels*cache_info->columns;
4624 q+=cache_info->number_channels*nexus_info->region.width;
4631 Read pixels from disk.
4633 LockSemaphoreInfo(cache_info->file_semaphore);
4634 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4636 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4637 cache_info->cache_filename);
4638 UnlockSemaphoreInfo(cache_info->file_semaphore);
4639 return(MagickFalse);
4641 if ((cache_info->columns == nexus_info->region.width) &&
4642 (extent <= MagickMaxBufferExtent))
4647 for (y=0; y < (ssize_t) region.height; y++)
4649 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4650 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4651 if (count != (MagickOffsetType) length)
4653 offset+=cache_info->columns;
4654 q+=cache_info->number_channels*nexus_info->region.width;
4656 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4657 (void) ClosePixelCacheOnDisk(cache_info);
4658 UnlockSemaphoreInfo(cache_info->file_semaphore);
4661 case DistributedCache:
4664 Read pixels from distributed cache.
4666 LockSemaphoreInfo(cache_info->file_semaphore);
4668 for (y=0; y < (ssize_t) region.height; y++)
4670 count=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4671 length,(unsigned char *) q);
4672 if (count != (MagickOffsetType) length)
4674 q+=cache_info->number_channels*nexus_info->region.width;
4677 UnlockSemaphoreInfo(cache_info->file_semaphore);
4683 if (y < (ssize_t) region.height)
4685 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4686 cache_info->cache_filename);
4687 return(MagickFalse);
4689 if ((cache_info->debug != MagickFalse) &&
4690 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4691 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4692 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4693 nexus_info->region.width,(double) nexus_info->region.height,(double)
4694 nexus_info->region.x,(double) nexus_info->region.y);
4699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703 + R e f e r e n c e P i x e l C a c h e %
4707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4709 % ReferencePixelCache() increments the reference count associated with the
4710 % pixel cache returning a pointer to the cache.
4712 % The format of the ReferencePixelCache method is:
4714 % Cache ReferencePixelCache(Cache cache_info)
4716 % A description of each parameter follows:
4718 % o cache_info: the pixel cache.
4721 MagickPrivate Cache ReferencePixelCache(Cache cache)
4726 assert(cache != (Cache *) NULL);
4727 cache_info=(CacheInfo *) cache;
4728 assert(cache_info->signature == MagickSignature);
4729 LockSemaphoreInfo(cache_info->semaphore);
4730 cache_info->reference_count++;
4731 UnlockSemaphoreInfo(cache_info->semaphore);
4736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4740 + S e t P i x e l C a c h e M e t h o d s %
4744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4746 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4748 % The format of the SetPixelCacheMethods() method is:
4750 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4752 % A description of each parameter follows:
4754 % o cache: the pixel cache.
4756 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4759 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4764 GetOneAuthenticPixelFromHandler
4765 get_one_authentic_pixel_from_handler;
4767 GetOneVirtualPixelFromHandler
4768 get_one_virtual_pixel_from_handler;
4771 Set cache pixel methods.
4773 assert(cache != (Cache) NULL);
4774 assert(cache_methods != (CacheMethods *) NULL);
4775 cache_info=(CacheInfo *) cache;
4776 assert(cache_info->signature == MagickSignature);
4777 if (cache_info->debug != MagickFalse)
4778 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4779 cache_info->filename);
4780 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4781 cache_info->methods.get_virtual_pixel_handler=
4782 cache_methods->get_virtual_pixel_handler;
4783 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4784 cache_info->methods.destroy_pixel_handler=
4785 cache_methods->destroy_pixel_handler;
4786 if (cache_methods->get_virtual_metacontent_from_handler !=
4787 (GetVirtualMetacontentFromHandler) NULL)
4788 cache_info->methods.get_virtual_metacontent_from_handler=
4789 cache_methods->get_virtual_metacontent_from_handler;
4790 if (cache_methods->get_authentic_pixels_handler !=
4791 (GetAuthenticPixelsHandler) NULL)
4792 cache_info->methods.get_authentic_pixels_handler=
4793 cache_methods->get_authentic_pixels_handler;
4794 if (cache_methods->queue_authentic_pixels_handler !=
4795 (QueueAuthenticPixelsHandler) NULL)
4796 cache_info->methods.queue_authentic_pixels_handler=
4797 cache_methods->queue_authentic_pixels_handler;
4798 if (cache_methods->sync_authentic_pixels_handler !=
4799 (SyncAuthenticPixelsHandler) NULL)
4800 cache_info->methods.sync_authentic_pixels_handler=
4801 cache_methods->sync_authentic_pixels_handler;
4802 if (cache_methods->get_authentic_pixels_from_handler !=
4803 (GetAuthenticPixelsFromHandler) NULL)
4804 cache_info->methods.get_authentic_pixels_from_handler=
4805 cache_methods->get_authentic_pixels_from_handler;
4806 if (cache_methods->get_authentic_metacontent_from_handler !=
4807 (GetAuthenticMetacontentFromHandler) NULL)
4808 cache_info->methods.get_authentic_metacontent_from_handler=
4809 cache_methods->get_authentic_metacontent_from_handler;
4810 get_one_virtual_pixel_from_handler=
4811 cache_info->methods.get_one_virtual_pixel_from_handler;
4812 if (get_one_virtual_pixel_from_handler !=
4813 (GetOneVirtualPixelFromHandler) NULL)
4814 cache_info->methods.get_one_virtual_pixel_from_handler=
4815 cache_methods->get_one_virtual_pixel_from_handler;
4816 get_one_authentic_pixel_from_handler=
4817 cache_methods->get_one_authentic_pixel_from_handler;
4818 if (get_one_authentic_pixel_from_handler !=
4819 (GetOneAuthenticPixelFromHandler) NULL)
4820 cache_info->methods.get_one_authentic_pixel_from_handler=
4821 cache_methods->get_one_authentic_pixel_from_handler;
4825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4829 + S e t P i x e l C a c h e N e x u s P i x e l s %
4833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4835 % SetPixelCacheNexusPixels() defines the region of the cache for the
4836 % specified cache nexus.
4838 % The format of the SetPixelCacheNexusPixels() method is:
4840 % Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4841 % const RectangleInfo *region,NexusInfo *nexus_info,
4842 % ExceptionInfo *exception)
4844 % A description of each parameter follows:
4846 % o image: the image.
4848 % o mode: ReadMode, WriteMode, or IOMode.
4850 % o region: A pointer to the RectangleInfo structure that defines the
4851 % region of this particular cache nexus.
4853 % o nexus_info: the cache nexus to set.
4855 % o exception: return any errors or warnings in this structure.
4859 static inline MagickBooleanType AcquireCacheNexusPixels(
4860 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4861 ExceptionInfo *exception)
4863 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4864 return(MagickFalse);
4865 nexus_info->mapped=MagickFalse;
4866 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4867 (size_t) nexus_info->length));
4868 if (nexus_info->cache == (Quantum *) NULL)
4870 nexus_info->mapped=MagickTrue;
4871 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4872 nexus_info->length);
4874 if (nexus_info->cache == (Quantum *) NULL)
4876 (void) ThrowMagickException(exception,GetMagickModule(),
4877 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4878 cache_info->filename);
4879 return(MagickFalse);
4884 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4887 if (mode == ReadMode)
4889 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4892 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4895 static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4896 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4908 cache_info=(CacheInfo *) image->cache;
4909 assert(cache_info->signature == MagickSignature);
4910 if (cache_info->type == UndefinedCache)
4911 return((Quantum *) NULL);
4912 nexus_info->region=(*region);
4913 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4919 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4920 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4921 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4922 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4923 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4924 ((nexus_info->region.width == cache_info->columns) ||
4925 ((nexus_info->region.width % cache_info->columns) == 0)))))
4931 Pixels are accessed directly from memory.
4933 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4934 nexus_info->region.x;
4935 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4937 nexus_info->metacontent=(void *) NULL;
4938 if (cache_info->metacontent_extent != 0)
4939 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4940 offset*cache_info->metacontent_extent;
4941 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4942 return(nexus_info->pixels);
4946 Pixels are stored in a cache region until they are synced to the cache.
4948 number_pixels=(MagickSizeType) nexus_info->region.width*
4949 nexus_info->region.height;
4950 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4951 if (cache_info->metacontent_extent != 0)
4952 length+=number_pixels*cache_info->metacontent_extent;
4953 if (nexus_info->cache == (Quantum *) NULL)
4955 nexus_info->length=length;
4956 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4957 if (status == MagickFalse)
4959 nexus_info->length=0;
4960 return((Quantum *) NULL);
4964 if (nexus_info->length != length)
4966 RelinquishCacheNexusPixels(nexus_info);
4967 nexus_info->length=length;
4968 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4969 if (status == MagickFalse)
4971 nexus_info->length=0;
4972 return((Quantum *) NULL);
4975 nexus_info->pixels=nexus_info->cache;
4976 nexus_info->metacontent=(void *) NULL;
4977 if (cache_info->metacontent_extent != 0)
4978 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4979 cache_info->number_channels);
4980 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4981 return(nexus_info->pixels);
4985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4989 % 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 %
4993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4995 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4996 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4997 % access that is outside the boundaries of the image cache.
4999 % The format of the SetPixelCacheVirtualMethod() method is:
5001 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5002 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5004 % A description of each parameter follows:
5006 % o image: the image.
5008 % o virtual_pixel_method: choose the type of virtual pixel.
5010 % o exception: return any errors or warnings in this structure.
5014 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
5015 ExceptionInfo *exception)
5029 assert(image != (Image *) NULL);
5030 assert(image->signature == MagickSignature);
5031 if (image->debug != MagickFalse)
5032 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5033 assert(image->cache != (Cache) NULL);
5034 cache_info=(CacheInfo *) image->cache;
5035 assert(cache_info->signature == MagickSignature);
5036 image->alpha_trait=BlendPixelTrait;
5038 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
5039 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5040 #pragma omp parallel for schedule(static,4) shared(status) \
5041 magick_threads(image,image,1,1)
5043 for (y=0; y < (ssize_t) image->rows; y++)
5051 if (status == MagickFalse)
5053 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5054 if (q == (Quantum *) NULL)
5059 for (x=0; x < (ssize_t) image->columns; x++)
5061 SetPixelAlpha(image,alpha,q);
5062 q+=GetPixelChannels(image);
5064 status=SyncCacheViewAuthenticPixels(image_view,exception);
5066 image_view=DestroyCacheView(image_view);
5070 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5071 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5079 assert(image != (Image *) NULL);
5080 assert(image->signature == MagickSignature);
5081 if (image->debug != MagickFalse)
5082 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5083 assert(image->cache != (Cache) NULL);
5084 cache_info=(CacheInfo *) image->cache;
5085 assert(cache_info->signature == MagickSignature);
5086 method=cache_info->virtual_pixel_method;
5087 cache_info->virtual_pixel_method=virtual_pixel_method;
5088 if ((image->columns != 0) && (image->rows != 0))
5089 switch (virtual_pixel_method)
5091 case BackgroundVirtualPixelMethod:
5093 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
5094 (image->alpha_trait != BlendPixelTrait))
5095 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5096 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
5097 (IsGrayColorspace(image->colorspace) != MagickFalse))
5098 (void) TransformImageColorspace(image,RGBColorspace,exception);
5101 case TransparentVirtualPixelMethod:
5103 if (image->alpha_trait != BlendPixelTrait)
5104 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5118 + 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 %
5122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5124 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5125 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5126 % is synced, otherwise MagickFalse.
5128 % The format of the SyncAuthenticPixelCacheNexus() method is:
5130 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5131 % NexusInfo *nexus_info,ExceptionInfo *exception)
5133 % A description of each parameter follows:
5135 % o image: the image.
5137 % o nexus_info: the cache nexus to sync.
5139 % o exception: return any errors or warnings in this structure.
5142 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5143 NexusInfo *nexus_info,ExceptionInfo *exception)
5152 Transfer pixels to the cache.
5154 assert(image != (Image *) NULL);
5155 assert(image->signature == MagickSignature);
5156 if (image->cache == (Cache) NULL)
5157 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5158 cache_info=(CacheInfo *) image->cache;
5159 assert(cache_info->signature == MagickSignature);
5160 if (cache_info->type == UndefinedCache)
5161 return(MagickFalse);
5162 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5164 assert(cache_info->signature == MagickSignature);
5165 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5166 if ((cache_info->metacontent_extent != 0) &&
5167 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5168 return(MagickFalse);
5173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5177 + S y n c A u t h e n t i c P i x e l C a c h e %
5181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5183 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5184 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5185 % otherwise MagickFalse.
5187 % The format of the SyncAuthenticPixelsCache() method is:
5189 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5190 % ExceptionInfo *exception)
5192 % A description of each parameter follows:
5194 % o image: the image.
5196 % o exception: return any errors or warnings in this structure.
5199 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5200 ExceptionInfo *exception)
5206 id = GetOpenMPThreadId();
5211 assert(image != (Image *) NULL);
5212 assert(image->signature == MagickSignature);
5213 assert(image->cache != (Cache) NULL);
5214 cache_info=(CacheInfo *) image->cache;
5215 assert(cache_info->signature == MagickSignature);
5216 assert(id < (int) cache_info->number_threads);
5217 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5227 % S y n c A u t h e n t i c P i x e l s %
5231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5233 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5234 % The method returns MagickTrue if the pixel region is flushed, otherwise
5237 % The format of the SyncAuthenticPixels() method is:
5239 % MagickBooleanType SyncAuthenticPixels(Image *image,
5240 % ExceptionInfo *exception)
5242 % A description of each parameter follows:
5244 % o image: the image.
5246 % o exception: return any errors or warnings in this structure.
5249 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5250 ExceptionInfo *exception)
5256 id = GetOpenMPThreadId();
5261 assert(image != (Image *) NULL);
5262 assert(image->signature == MagickSignature);
5263 assert(image->cache != (Cache) NULL);
5264 cache_info=(CacheInfo *) image->cache;
5265 assert(cache_info->signature == MagickSignature);
5266 if (cache_info->methods.sync_authentic_pixels_handler !=
5267 (SyncAuthenticPixelsHandler) NULL)
5269 status=cache_info->methods.sync_authentic_pixels_handler(image,
5273 assert(id < (int) cache_info->number_threads);
5274 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5284 + S y n c I m a g e P i x e l C a c h e %
5288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5290 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5291 % The method returns MagickTrue if the pixel region is flushed, otherwise
5294 % The format of the SyncImagePixelCache() method is:
5296 % MagickBooleanType SyncImagePixelCache(Image *image,
5297 % ExceptionInfo *exception)
5299 % A description of each parameter follows:
5301 % o image: the image.
5303 % o exception: return any errors or warnings in this structure.
5306 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5307 ExceptionInfo *exception)
5312 assert(image != (Image *) NULL);
5313 assert(exception != (ExceptionInfo *) NULL);
5314 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5315 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5323 + 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 %
5327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5329 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5330 % of the pixel cache.
5332 % The format of the WritePixelCacheMetacontent() method is:
5334 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5335 % NexusInfo *nexus_info,ExceptionInfo *exception)
5337 % A description of each parameter follows:
5339 % o cache_info: the pixel cache.
5341 % o nexus_info: the cache nexus to write the meta-content.
5343 % o exception: return any errors or warnings in this structure.
5346 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5347 NexusInfo *nexus_info,ExceptionInfo *exception)
5360 register const unsigned char
5366 if (cache_info->metacontent_extent == 0)
5367 return(MagickFalse);
5368 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5370 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5371 nexus_info->region.x;
5372 length=(MagickSizeType) nexus_info->region.width*
5373 cache_info->metacontent_extent;
5374 extent=(MagickSizeType) length*nexus_info->region.height;
5375 region=nexus_info->region;
5377 p=(unsigned char *) nexus_info->metacontent;
5378 switch (cache_info->type)
5383 register unsigned char
5387 Write associated pixels to memory.
5389 if ((cache_info->columns == nexus_info->region.width) &&
5390 (extent == (MagickSizeType) ((size_t) extent)))
5395 q=(unsigned char *) cache_info->metacontent+offset*
5396 cache_info->metacontent_extent;
5397 for (y=0; y < (ssize_t) region.height; y++)
5399 (void) memcpy(q,p,(size_t) length);
5400 p+=nexus_info->region.width*cache_info->metacontent_extent;
5401 q+=cache_info->columns*cache_info->metacontent_extent;
5408 Write associated pixels to disk.
5410 LockSemaphoreInfo(cache_info->file_semaphore);
5411 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5413 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5414 cache_info->cache_filename);
5415 UnlockSemaphoreInfo(cache_info->file_semaphore);
5416 return(MagickFalse);
5418 if ((cache_info->columns == nexus_info->region.width) &&
5419 (extent <= MagickMaxBufferExtent))
5424 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5425 for (y=0; y < (ssize_t) region.height; y++)
5427 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5428 cache_info->number_channels*sizeof(Quantum)+offset*
5429 cache_info->metacontent_extent,length,(const unsigned char *) p);
5430 if (count != (MagickOffsetType) length)
5432 p+=cache_info->metacontent_extent*nexus_info->region.width;
5433 offset+=cache_info->columns;
5435 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5436 (void) ClosePixelCacheOnDisk(cache_info);
5437 UnlockSemaphoreInfo(cache_info->file_semaphore);
5440 case DistributedCache:
5443 Write metacontent to distributed cache.
5445 LockSemaphoreInfo(cache_info->file_semaphore);
5447 for (y=0; y < (ssize_t) region.height; y++)
5449 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5450 length,(const unsigned char *) p);
5451 if (count != (MagickOffsetType) length)
5453 p+=cache_info->metacontent_extent*nexus_info->region.width;
5456 UnlockSemaphoreInfo(cache_info->file_semaphore);
5462 if (y < (ssize_t) region.height)
5464 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5465 cache_info->cache_filename);
5466 return(MagickFalse);
5468 if ((cache_info->debug != MagickFalse) &&
5469 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5470 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5471 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5472 nexus_info->region.width,(double) nexus_info->region.height,(double)
5473 nexus_info->region.x,(double) nexus_info->region.y);
5478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5482 + W r i t e C a c h e P i x e l s %
5486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5488 % WritePixelCachePixels() writes image pixels to the specified region of the
5491 % The format of the WritePixelCachePixels() method is:
5493 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5494 % NexusInfo *nexus_info,ExceptionInfo *exception)
5496 % A description of each parameter follows:
5498 % o cache_info: the pixel cache.
5500 % o nexus_info: the cache nexus to write the pixels.
5502 % o exception: return any errors or warnings in this structure.
5505 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5506 NexusInfo *nexus_info,ExceptionInfo *exception)
5519 register const Quantum
5525 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5527 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5528 nexus_info->region.x;
5529 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5531 extent=length*nexus_info->region.height;
5532 region=nexus_info->region;
5534 p=nexus_info->pixels;
5535 switch (cache_info->type)
5544 Write pixels to memory.
5546 if ((cache_info->columns == nexus_info->region.width) &&
5547 (extent == (MagickSizeType) ((size_t) extent)))
5552 q=cache_info->pixels+offset*cache_info->number_channels;
5553 for (y=0; y < (ssize_t) region.height; y++)
5555 (void) memcpy(q,p,(size_t) length);
5556 p+=cache_info->number_channels*nexus_info->region.width;
5557 q+=cache_info->columns*cache_info->number_channels;
5564 Write pixels to disk.
5566 LockSemaphoreInfo(cache_info->file_semaphore);
5567 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5569 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5570 cache_info->cache_filename);
5571 UnlockSemaphoreInfo(cache_info->file_semaphore);
5572 return(MagickFalse);
5574 if ((cache_info->columns == nexus_info->region.width) &&
5575 (extent <= MagickMaxBufferExtent))
5580 for (y=0; y < (ssize_t) region.height; y++)
5582 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5583 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5585 if (count != (MagickOffsetType) length)
5587 p+=cache_info->number_channels*nexus_info->region.width;
5588 offset+=cache_info->columns;
5590 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5591 (void) ClosePixelCacheOnDisk(cache_info);
5592 UnlockSemaphoreInfo(cache_info->file_semaphore);
5595 case DistributedCache:
5598 Write pixels to distributed cache.
5600 LockSemaphoreInfo(cache_info->file_semaphore);
5602 for (y=0; y < (ssize_t) region.height; y++)
5604 count=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5605 length,(const unsigned char *) p);
5606 if (count != (MagickOffsetType) length)
5608 p+=cache_info->number_channels*nexus_info->region.width;
5611 UnlockSemaphoreInfo(cache_info->file_semaphore);
5617 if (y < (ssize_t) region.height)
5619 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5620 cache_info->cache_filename);
5621 return(MagickFalse);
5623 if ((cache_info->debug != MagickFalse) &&
5624 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5625 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5626 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5627 nexus_info->region.width,(double) nexus_info->region.height,(double)
5628 nexus_info->region.x,(double) nexus_info->region.y);