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)
826 cache_offset+=length;
827 if ((y < (ssize_t) clone_info->rows) &&
828 (x < (ssize_t) clone_info->columns))
829 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
841 Write a set of pixel channels.
843 channel=clone_info->channel_map[i].channel;
844 traits=cache_info->channel_map[channel].traits;
845 if (traits == UndefinedPixelTrait)
847 clone_offset+=sizeof(Quantum);
850 offset=cache_info->channel_map[channel].offset;
851 if ((clone_info->type == MemoryCache) ||
852 (clone_info->type == MapCache))
853 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
854 offset*sizeof(Quantum),sizeof(Quantum));
857 count=WritePixelCacheRegion(clone_info,clone_offset,
858 sizeof(Quantum),p+offset*sizeof(Quantum));
859 if ((MagickSizeType) count != sizeof(Quantum))
865 clone_offset+=sizeof(Quantum);
868 if (y < (ssize_t) clone_info->rows)
871 Set remaining columns as undefined.
873 length=clone_info->number_channels*sizeof(Quantum);
874 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
875 for ( ; x < (ssize_t) clone_info->columns; x++)
877 if ((clone_info->type == MemoryCache) ||
878 (clone_info->type == MapCache))
879 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
883 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
884 if ((MagickSizeType) count != length)
890 clone_offset+=length;
894 length=clone_info->number_channels*sizeof(Quantum);
895 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
896 for ( ; y < (ssize_t) clone_info->rows; y++)
899 Set remaining rows as undefined.
901 for (x=0; x < (ssize_t) clone_info->columns; x++)
903 if ((clone_info->type == MemoryCache) || (clone_info->type == MapCache))
904 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
908 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
909 if ((MagickSizeType) count != length)
915 clone_offset+=length;
918 if ((cache_info->metacontent_extent != 0) ||
919 (clone_info->metacontent_extent != 0))
924 for (y=0; y < (ssize_t) cache_info->rows; y++)
926 for (x=0; x < (ssize_t) cache_info->columns; x++)
929 Read a set of metacontent.
931 length=cache_info->metacontent_extent;
932 if ((cache_info->type == MemoryCache) ||
933 (cache_info->type == MapCache))
934 p=(unsigned char *) cache_info->pixels+cache_offset;
937 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
938 if ((MagickSizeType) count != length)
944 cache_offset+=length;
945 if ((y < (ssize_t) clone_info->rows) &&
946 (x < (ssize_t) clone_info->columns))
949 Write a set of metacontent.
951 length=clone_info->metacontent_extent;
952 if ((clone_info->type == MemoryCache) ||
953 (clone_info->type == MapCache))
954 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
958 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
959 if ((MagickSizeType) count != length)
965 clone_offset+=length;
968 length=clone_info->metacontent_extent;
969 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
970 for ( ; x < (ssize_t) clone_info->columns; x++)
973 Set remaining columns as undefined.
975 if ((clone_info->type == MemoryCache) ||
976 (clone_info->type == MapCache))
977 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
981 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
982 if ((MagickSizeType) count != length)
988 clone_offset+=length;
991 if (y < (ssize_t) clone_info->rows)
994 Set remaining rows as undefined.
996 length=clone_info->metacontent_extent;
997 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
998 for ( ; y < (ssize_t) clone_info->rows; y++)
1000 for (x=0; x < (ssize_t) clone_info->columns; x++)
1002 if ((clone_info->type == MemoryCache) ||
1003 (clone_info->type == MapCache))
1004 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1008 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1010 if ((MagickSizeType) count != length)
1016 clone_offset+=length;
1021 if (clone_info->type == DiskCache)
1022 (void) ClosePixelCacheOnDisk(clone_info);
1023 if (cache_info->type == DiskCache)
1024 (void) ClosePixelCacheOnDisk(cache_info);
1025 blob=(unsigned char *) RelinquishMagickMemory(blob);
1029 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1030 CacheInfo *cache_info,ExceptionInfo *exception)
1036 if (cache_info->debug != MagickFalse)
1039 message[MaxTextExtent];
1041 (void) FormatLocaleString(message,MaxTextExtent,"%s => %s",
1042 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
1043 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
1044 (void) LogMagickEvent(CacheEvent,GetMagickModule(),message);
1046 if (cache_info->type == PingCache)
1048 if (cache_info->type == DistributedCache)
1049 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1050 p=cache_info->channel_map;
1051 q=clone_info->channel_map;
1052 if ((cache_info->columns == clone_info->columns) &&
1053 (cache_info->rows == clone_info->rows) &&
1054 (cache_info->number_channels == clone_info->number_channels) &&
1055 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1056 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1057 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1058 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1062 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1066 + C l o n e P i x e l C a c h e M e t h o d s %
1070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1072 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1075 % The format of the ClonePixelCacheMethods() method is:
1077 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1079 % A description of each parameter follows:
1081 % o clone: Specifies a pointer to a Cache structure.
1083 % o cache: the pixel cache.
1086 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1092 assert(clone != (Cache) NULL);
1093 source_info=(CacheInfo *) clone;
1094 assert(source_info->signature == MagickSignature);
1095 if (source_info->debug != MagickFalse)
1096 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1097 source_info->filename);
1098 assert(cache != (Cache) NULL);
1099 cache_info=(CacheInfo *) cache;
1100 assert(cache_info->signature == MagickSignature);
1101 source_info->methods=cache_info->methods;
1105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1109 + D e s t r o y I m a g e P i x e l C a c h e %
1113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1115 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1117 % The format of the DestroyImagePixelCache() method is:
1119 % void DestroyImagePixelCache(Image *image)
1121 % A description of each parameter follows:
1123 % o image: the image.
1126 static void DestroyImagePixelCache(Image *image)
1128 assert(image != (Image *) NULL);
1129 assert(image->signature == MagickSignature);
1130 if (image->debug != MagickFalse)
1131 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1132 if (image->cache == (void *) NULL)
1134 image->cache=DestroyPixelCache(image->cache);
1138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1142 + D e s t r o y I m a g e P i x e l s %
1146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1148 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1150 % The format of the DestroyImagePixels() method is:
1152 % void DestroyImagePixels(Image *image)
1154 % A description of each parameter follows:
1156 % o image: the image.
1159 MagickExport void DestroyImagePixels(Image *image)
1164 assert(image != (const Image *) NULL);
1165 assert(image->signature == MagickSignature);
1166 if (image->debug != MagickFalse)
1167 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1168 assert(image->cache != (Cache) NULL);
1169 cache_info=(CacheInfo *) image->cache;
1170 assert(cache_info->signature == MagickSignature);
1171 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1173 cache_info->methods.destroy_pixel_handler(image);
1176 image->cache=DestroyPixelCache(image->cache);
1180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1184 + D e s t r o y P i x e l C a c h e %
1188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1190 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1192 % The format of the DestroyPixelCache() method is:
1194 % Cache DestroyPixelCache(Cache cache)
1196 % A description of each parameter follows:
1198 % o cache: the pixel cache.
1202 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1204 switch (cache_info->type)
1208 if (cache_info->mapped == MagickFalse)
1209 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
1210 cache_info->pixels);
1212 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1213 (size_t) cache_info->length);
1214 RelinquishMagickResource(MemoryResource,cache_info->length);
1219 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1220 cache_info->length);
1221 if (cache_info->mode != ReadMode)
1222 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1223 *cache_info->cache_filename='\0';
1224 RelinquishMagickResource(MapResource,cache_info->length);
1228 if (cache_info->file != -1)
1229 (void) ClosePixelCacheOnDisk(cache_info);
1230 if (cache_info->mode != ReadMode)
1231 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1232 *cache_info->cache_filename='\0';
1233 RelinquishMagickResource(DiskResource,cache_info->length);
1236 case DistributedCache:
1238 (void) RelinquishDistributePixelCache(cache_info->server_info);
1244 cache_info->type=UndefinedCache;
1245 cache_info->mapped=MagickFalse;
1246 cache_info->metacontent=(void *) NULL;
1249 MagickPrivate Cache DestroyPixelCache(Cache cache)
1254 assert(cache != (Cache) NULL);
1255 cache_info=(CacheInfo *) cache;
1256 assert(cache_info->signature == MagickSignature);
1257 if (cache_info->debug != MagickFalse)
1258 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1259 cache_info->filename);
1260 LockSemaphoreInfo(cache_info->semaphore);
1261 cache_info->reference_count--;
1262 if (cache_info->reference_count != 0)
1264 UnlockSemaphoreInfo(cache_info->semaphore);
1265 return((Cache) NULL);
1267 UnlockSemaphoreInfo(cache_info->semaphore);
1268 if (cache_info->debug != MagickFalse)
1271 message[MaxTextExtent];
1273 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1274 cache_info->filename);
1275 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1277 RelinquishPixelCachePixels(cache_info);
1278 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
1279 cache_info->server_info=DestroyDistributeCacheInfo(cache_info->server_info);
1280 if (cache_info->nexus_info != (NexusInfo **) NULL)
1281 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1282 cache_info->number_threads);
1283 if (cache_info->random_info != (RandomInfo *) NULL)
1284 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1285 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
1286 DestroySemaphoreInfo(&cache_info->file_semaphore);
1287 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1288 DestroySemaphoreInfo(&cache_info->semaphore);
1289 cache_info->signature=(~MagickSignature);
1290 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1300 + D e s t r o y P i x e l C a c h e N e x u s %
1304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1306 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1308 % The format of the DestroyPixelCacheNexus() method is:
1310 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1311 % const size_t number_threads)
1313 % A description of each parameter follows:
1315 % o nexus_info: the nexus to destroy.
1317 % o number_threads: the number of nexus threads.
1321 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1323 if (nexus_info->mapped == MagickFalse)
1324 (void) RelinquishAlignedMemory(nexus_info->cache);
1326 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1327 nexus_info->cache=(Quantum *) NULL;
1328 nexus_info->pixels=(Quantum *) NULL;
1329 nexus_info->metacontent=(void *) NULL;
1330 nexus_info->length=0;
1331 nexus_info->mapped=MagickFalse;
1334 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1335 const size_t number_threads)
1340 assert(nexus_info != (NexusInfo **) NULL);
1341 for (i=0; i < (ssize_t) number_threads; i++)
1343 if (nexus_info[i]->cache != (Quantum *) NULL)
1344 RelinquishCacheNexusPixels(nexus_info[i]);
1345 nexus_info[i]->signature=(~MagickSignature);
1347 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1348 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1357 % G e t A u t h e n t i c M e t a c o n t e n t %
1361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1363 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1364 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1365 % returned if the associated pixels are not available.
1367 % The format of the GetAuthenticMetacontent() method is:
1369 % void *GetAuthenticMetacontent(const Image *image)
1371 % A description of each parameter follows:
1373 % o image: the image.
1376 MagickExport void *GetAuthenticMetacontent(const Image *image)
1382 id = GetOpenMPThreadId();
1387 assert(image != (const Image *) NULL);
1388 assert(image->signature == MagickSignature);
1389 assert(image->cache != (Cache) NULL);
1390 cache_info=(CacheInfo *) image->cache;
1391 assert(cache_info->signature == MagickSignature);
1392 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1393 (GetAuthenticMetacontentFromHandler) NULL)
1395 metacontent=cache_info->methods.
1396 get_authentic_metacontent_from_handler(image);
1397 return(metacontent);
1399 assert(id < (int) cache_info->number_threads);
1400 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1401 cache_info->nexus_info[id]);
1402 return(metacontent);
1406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410 + 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 %
1414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1416 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1417 % with the last call to QueueAuthenticPixelsCache() or
1418 % GetAuthenticPixelsCache().
1420 % The format of the GetAuthenticMetacontentFromCache() method is:
1422 % void *GetAuthenticMetacontentFromCache(const Image *image)
1424 % A description of each parameter follows:
1426 % o image: the image.
1429 static void *GetAuthenticMetacontentFromCache(const Image *image)
1435 id = GetOpenMPThreadId();
1440 assert(image != (const Image *) NULL);
1441 assert(image->signature == MagickSignature);
1442 assert(image->cache != (Cache) NULL);
1443 cache_info=(CacheInfo *) image->cache;
1444 assert(cache_info->signature == MagickSignature);
1445 assert(id < (int) cache_info->number_threads);
1446 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1447 cache_info->nexus_info[id]);
1448 return(metacontent);
1452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1456 + 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 %
1460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1462 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1463 % disk pixel cache as defined by the geometry parameters. A pointer to the
1464 % pixels is returned if the pixels are transferred, otherwise a NULL is
1467 % The format of the GetAuthenticPixelCacheNexus() method is:
1469 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1470 % const ssize_t y,const size_t columns,const size_t rows,
1471 % NexusInfo *nexus_info,ExceptionInfo *exception)
1473 % A description of each parameter follows:
1475 % o image: the image.
1477 % o x,y,columns,rows: These values define the perimeter of a region of
1480 % o nexus_info: the cache nexus to return.
1482 % o exception: return any errors or warnings in this structure.
1486 static inline MagickBooleanType IsPixelAuthentic(
1487 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1495 if (cache_info->type == PingCache)
1497 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1498 nexus_info->region.x;
1499 status=nexus_info->pixels == (cache_info->pixels+offset*
1500 cache_info->number_channels) ? MagickTrue : MagickFalse;
1504 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1505 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1506 NexusInfo *nexus_info,ExceptionInfo *exception)
1515 Transfer pixels from the cache.
1517 assert(image != (Image *) NULL);
1518 assert(image->signature == MagickSignature);
1519 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1521 if (q == (Quantum *) NULL)
1522 return((Quantum *) NULL);
1523 cache_info=(CacheInfo *) image->cache;
1524 assert(cache_info->signature == MagickSignature);
1525 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1527 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1528 return((Quantum *) NULL);
1529 if (cache_info->metacontent_extent != 0)
1530 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1531 return((Quantum *) NULL);
1536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540 + 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 %
1544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1547 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1549 % The format of the GetAuthenticPixelsFromCache() method is:
1551 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1553 % A description of each parameter follows:
1555 % o image: the image.
1558 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1564 id = GetOpenMPThreadId();
1566 assert(image != (const Image *) NULL);
1567 assert(image->signature == MagickSignature);
1568 assert(image->cache != (Cache) NULL);
1569 cache_info=(CacheInfo *) image->cache;
1570 assert(cache_info->signature == MagickSignature);
1571 assert(id < (int) cache_info->number_threads);
1572 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1576 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1580 % G e t A u t h e n t i c P i x e l Q u e u e %
1584 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1586 % GetAuthenticPixelQueue() returns the authentic pixels associated
1587 % corresponding with the last call to QueueAuthenticPixels() or
1588 % GetAuthenticPixels().
1590 % The format of the GetAuthenticPixelQueue() method is:
1592 % Quantum *GetAuthenticPixelQueue(const Image image)
1594 % A description of each parameter follows:
1596 % o image: the image.
1599 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1605 id = GetOpenMPThreadId();
1607 assert(image != (const Image *) NULL);
1608 assert(image->signature == MagickSignature);
1609 assert(image->cache != (Cache) NULL);
1610 cache_info=(CacheInfo *) image->cache;
1611 assert(cache_info->signature == MagickSignature);
1612 if (cache_info->methods.get_authentic_pixels_from_handler !=
1613 (GetAuthenticPixelsFromHandler) NULL)
1614 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1615 assert(id < (int) cache_info->number_threads);
1616 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624 % G e t A u t h e n t i c P i x e l s %
1627 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1630 % region is successfully accessed, a pointer to a Quantum array
1631 % representing the region is returned, otherwise NULL is returned.
1633 % The returned pointer may point to a temporary working copy of the pixels
1634 % or it may point to the original pixels in memory. Performance is maximized
1635 % if the selected region is part of one row, or one or more full rows, since
1636 % then there is opportunity to access the pixels in-place (without a copy)
1637 % if the image is in memory, or in a memory-mapped file. The returned pointer
1638 % must *never* be deallocated by the user.
1640 % Pixels accessed via the returned pointer represent a simple array of type
1641 % Quantum. If the image has corresponding metacontent,call
1642 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1643 % meta-content corresponding to the region. Once the Quantum array has
1644 % been updated, the changes must be saved back to the underlying image using
1645 % SyncAuthenticPixels() or they may be lost.
1647 % The format of the GetAuthenticPixels() method is:
1649 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1650 % const ssize_t y,const size_t columns,const size_t rows,
1651 % ExceptionInfo *exception)
1653 % A description of each parameter follows:
1655 % o image: the image.
1657 % o x,y,columns,rows: These values define the perimeter of a region of
1660 % o exception: return any errors or warnings in this structure.
1663 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1664 const ssize_t y,const size_t columns,const size_t rows,
1665 ExceptionInfo *exception)
1671 id = GetOpenMPThreadId();
1676 assert(image != (Image *) NULL);
1677 assert(image->signature == MagickSignature);
1678 assert(image->cache != (Cache) NULL);
1679 cache_info=(CacheInfo *) image->cache;
1680 assert(cache_info->signature == MagickSignature);
1681 if (cache_info->methods.get_authentic_pixels_handler !=
1682 (GetAuthenticPixelsHandler) NULL)
1684 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1688 assert(id < (int) cache_info->number_threads);
1689 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1690 cache_info->nexus_info[id],exception);
1695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1699 + G e t A u t h e n t i c P i x e l s C a c h e %
1703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1705 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1706 % as defined by the geometry parameters. A pointer to the pixels is returned
1707 % if the pixels are transferred, otherwise a NULL is returned.
1709 % The format of the GetAuthenticPixelsCache() method is:
1711 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1712 % const ssize_t y,const size_t columns,const size_t rows,
1713 % ExceptionInfo *exception)
1715 % A description of each parameter follows:
1717 % o image: the image.
1719 % o x,y,columns,rows: These values define the perimeter of a region of
1722 % o exception: return any errors or warnings in this structure.
1725 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1726 const ssize_t y,const size_t columns,const size_t rows,
1727 ExceptionInfo *exception)
1733 id = GetOpenMPThreadId();
1738 assert(image != (const Image *) NULL);
1739 assert(image->signature == MagickSignature);
1740 assert(image->cache != (Cache) NULL);
1741 cache_info=(CacheInfo *) image->cache;
1742 if (cache_info == (Cache) NULL)
1743 return((Quantum *) NULL);
1744 assert(cache_info->signature == MagickSignature);
1745 assert(id < (int) cache_info->number_threads);
1746 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1747 cache_info->nexus_info[id],exception);
1752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1756 + G e t I m a g e E x t e n t %
1760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1762 % GetImageExtent() returns the extent of the pixels associated corresponding
1763 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1765 % The format of the GetImageExtent() method is:
1767 % MagickSizeType GetImageExtent(const Image *image)
1769 % A description of each parameter follows:
1771 % o image: the image.
1774 MagickExport MagickSizeType GetImageExtent(const Image *image)
1780 id = GetOpenMPThreadId();
1782 assert(image != (Image *) NULL);
1783 assert(image->signature == MagickSignature);
1784 if (image->debug != MagickFalse)
1785 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1786 assert(image->cache != (Cache) NULL);
1787 cache_info=(CacheInfo *) image->cache;
1788 assert(cache_info->signature == MagickSignature);
1789 assert(id < (int) cache_info->number_threads);
1790 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1798 + G e t I m a g e P i x e l C a c h e %
1802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1804 % GetImagePixelCache() ensures that there is only a single reference to the
1805 % pixel cache to be modified, updating the provided cache pointer to point to
1806 % a clone of the original pixel cache if necessary.
1808 % The format of the GetImagePixelCache method is:
1810 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1811 % ExceptionInfo *exception)
1813 % A description of each parameter follows:
1815 % o image: the image.
1817 % o clone: any value other than MagickFalse clones the cache pixels.
1819 % o exception: return any errors or warnings in this structure.
1823 static inline MagickBooleanType ValidatePixelCacheMorphology(
1824 const Image *restrict image)
1827 *restrict cache_info;
1829 const PixelChannelMap
1834 Does the image match the pixel cache morphology?
1836 cache_info=(CacheInfo *) image->cache;
1837 p=image->channel_map;
1838 q=cache_info->channel_map;
1839 if ((image->storage_class != cache_info->storage_class) ||
1840 (image->colorspace != cache_info->colorspace) ||
1841 (image->alpha_trait != cache_info->alpha_trait) ||
1842 (image->mask != cache_info->mask) ||
1843 (image->columns != cache_info->columns) ||
1844 (image->rows != cache_info->rows) ||
1845 (image->number_channels != cache_info->number_channels) ||
1846 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1847 (image->metacontent_extent != cache_info->metacontent_extent) ||
1848 (cache_info->nexus_info == (NexusInfo **) NULL))
1849 return(MagickFalse);
1853 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1854 ExceptionInfo *exception)
1863 static MagickSizeType
1869 cache_timestamp = 0;
1872 LockSemaphoreInfo(image->semaphore);
1873 if (cpu_throttle == 0)
1879 Set CPU throttle in milleseconds.
1881 cpu_throttle=MagickResourceInfinity;
1882 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1883 if (limit == (char *) NULL)
1884 limit=GetPolicyValue("throttle");
1885 if (limit != (char *) NULL)
1887 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1888 limit=DestroyString(limit);
1891 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1892 MagickDelay(cpu_throttle);
1893 if (time_limit == 0)
1896 Set the expire time in seconds.
1898 time_limit=GetMagickResourceLimit(TimeResource);
1899 cache_timestamp=time((time_t *) NULL);
1901 if ((time_limit != MagickResourceInfinity) &&
1902 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1903 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1904 assert(image->cache != (Cache) NULL);
1905 cache_info=(CacheInfo *) image->cache;
1906 destroy=MagickFalse;
1907 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1909 LockSemaphoreInfo(cache_info->semaphore);
1910 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1921 clone_image=(*image);
1922 clone_image.semaphore=AllocateSemaphoreInfo();
1923 clone_image.reference_count=1;
1924 clone_image.cache=ClonePixelCache(cache_info);
1925 clone_info=(CacheInfo *) clone_image.cache;
1926 status=OpenPixelCache(&clone_image,IOMode,exception);
1927 if (status != MagickFalse)
1929 if (clone != MagickFalse)
1930 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1931 if (status != MagickFalse)
1933 if (cache_info->reference_count == 1)
1934 cache_info->nexus_info=(NexusInfo **) NULL;
1936 image->cache=clone_image.cache;
1939 DestroySemaphoreInfo(&clone_image.semaphore);
1941 UnlockSemaphoreInfo(cache_info->semaphore);
1943 if (destroy != MagickFalse)
1944 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1945 if (status != MagickFalse)
1948 Ensure the image matches the pixel cache morphology.
1950 image->taint=MagickTrue;
1951 image->type=UndefinedType;
1952 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1954 status=OpenPixelCache(image,IOMode,exception);
1955 cache_info=(CacheInfo *) image->cache;
1956 if (cache_info->type == DiskCache)
1957 (void) ClosePixelCacheOnDisk(cache_info);
1960 UnlockSemaphoreInfo(image->semaphore);
1961 if (status == MagickFalse)
1962 return((Cache) NULL);
1963 return(image->cache);
1967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1971 + G e t I m a g e P i x e l C a c h e T y p e %
1975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1977 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1978 % DiskCache, MemoryCache, MapCache, or PingCache.
1980 % The format of the GetImagePixelCacheType() method is:
1982 % CacheType GetImagePixelCacheType(const Image *image)
1984 % A description of each parameter follows:
1986 % o image: the image.
1989 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1994 assert(image != (Image *) NULL);
1995 assert(image->signature == MagickSignature);
1996 assert(image->cache != (Cache) NULL);
1997 cache_info=(CacheInfo *) image->cache;
1998 assert(cache_info->signature == MagickSignature);
1999 return(cache_info->type);
2003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2007 % G e t O n e A u t h e n t i c P i x e l %
2011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2014 % location. The image background color is returned if an error occurs.
2016 % The format of the GetOneAuthenticPixel() method is:
2018 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2019 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2021 % A description of each parameter follows:
2023 % o image: the image.
2025 % o x,y: These values define the location of the pixel to return.
2027 % o pixel: return a pixel at the specified (x,y) location.
2029 % o exception: return any errors or warnings in this structure.
2032 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2033 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2044 assert(image != (Image *) NULL);
2045 assert(image->signature == MagickSignature);
2046 assert(image->cache != (Cache) NULL);
2047 cache_info=(CacheInfo *) image->cache;
2048 assert(cache_info->signature == MagickSignature);
2049 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2050 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2051 (GetOneAuthenticPixelFromHandler) NULL)
2052 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2054 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2055 if (q == (Quantum *) NULL)
2057 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2058 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2059 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2060 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2061 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2062 return(MagickFalse);
2064 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2069 channel=GetPixelChannelChannel(image,i);
2070 pixel[channel]=q[i];
2076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2080 + 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 %
2084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2086 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2087 % location. The image background color is returned if an error occurs.
2089 % The format of the GetOneAuthenticPixelFromCache() method is:
2091 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2092 % const ssize_t x,const ssize_t y,Quantum *pixel,
2093 % ExceptionInfo *exception)
2095 % A description of each parameter follows:
2097 % o image: the image.
2099 % o x,y: These values define the location of the pixel to return.
2101 % o pixel: return a pixel at the specified (x,y) location.
2103 % o exception: return any errors or warnings in this structure.
2106 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2107 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2113 id = GetOpenMPThreadId();
2121 assert(image != (const Image *) NULL);
2122 assert(image->signature == MagickSignature);
2123 assert(image->cache != (Cache) NULL);
2124 cache_info=(CacheInfo *) image->cache;
2125 assert(cache_info->signature == MagickSignature);
2126 assert(id < (int) cache_info->number_threads);
2127 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2128 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2130 if (q == (Quantum *) NULL)
2132 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2133 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2134 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2135 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2136 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2137 return(MagickFalse);
2139 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2144 channel=GetPixelChannelChannel(image,i);
2145 pixel[channel]=q[i];
2151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2155 % G e t O n e V i r t u a l P i x e l %
2159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2161 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2162 % (x,y) location. The image background color is returned if an error occurs.
2163 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2165 % The format of the GetOneVirtualPixel() method is:
2167 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2168 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2170 % A description of each parameter follows:
2172 % o image: the image.
2174 % o x,y: These values define the location of the pixel to return.
2176 % o pixel: return a pixel at the specified (x,y) location.
2178 % o exception: return any errors or warnings in this structure.
2181 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2182 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2188 id = GetOpenMPThreadId();
2196 assert(image != (const Image *) NULL);
2197 assert(image->signature == MagickSignature);
2198 assert(image->cache != (Cache) NULL);
2199 cache_info=(CacheInfo *) image->cache;
2200 assert(cache_info->signature == MagickSignature);
2201 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2202 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2203 (GetOneVirtualPixelFromHandler) NULL)
2204 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2205 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2206 assert(id < (int) cache_info->number_threads);
2207 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2208 1UL,1UL,cache_info->nexus_info[id],exception);
2209 if (p == (const Quantum *) NULL)
2211 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2212 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2213 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2214 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2215 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2216 return(MagickFalse);
2218 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2223 channel=GetPixelChannelChannel(image,i);
2224 pixel[channel]=p[i];
2230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2234 + 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 %
2238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2240 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2241 % specified (x,y) location. The image background color is returned if an
2244 % The format of the GetOneVirtualPixelFromCache() method is:
2246 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2247 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2248 % Quantum *pixel,ExceptionInfo *exception)
2250 % A description of each parameter follows:
2252 % o image: the image.
2254 % o virtual_pixel_method: the virtual pixel method.
2256 % o x,y: These values define the location of the pixel to return.
2258 % o pixel: return a pixel at the specified (x,y) location.
2260 % o exception: return any errors or warnings in this structure.
2263 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2264 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2265 Quantum *pixel,ExceptionInfo *exception)
2271 id = GetOpenMPThreadId();
2279 assert(image != (const Image *) NULL);
2280 assert(image->signature == MagickSignature);
2281 assert(image->cache != (Cache) NULL);
2282 cache_info=(CacheInfo *) image->cache;
2283 assert(cache_info->signature == MagickSignature);
2284 assert(id < (int) cache_info->number_threads);
2285 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2286 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2287 cache_info->nexus_info[id],exception);
2288 if (p == (const Quantum *) NULL)
2290 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2291 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2292 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2293 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2294 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2295 return(MagickFalse);
2297 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2302 channel=GetPixelChannelChannel(image,i);
2303 pixel[channel]=p[i];
2309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2313 % G e t O n e V i r t u a l P i x e l I n f o %
2317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2319 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2320 % location. The image background color is returned if an error occurs. If
2321 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2323 % The format of the GetOneVirtualPixelInfo() method is:
2325 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2326 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2327 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2329 % A description of each parameter follows:
2331 % o image: the image.
2333 % o virtual_pixel_method: the virtual pixel method.
2335 % o x,y: these values define the location of the pixel to return.
2337 % o pixel: return a pixel at the specified (x,y) location.
2339 % o exception: return any errors or warnings in this structure.
2342 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2343 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2344 PixelInfo *pixel,ExceptionInfo *exception)
2350 id = GetOpenMPThreadId();
2352 register const Quantum
2355 assert(image != (const Image *) NULL);
2356 assert(image->signature == MagickSignature);
2357 assert(image->cache != (Cache) NULL);
2358 cache_info=(CacheInfo *) image->cache;
2359 assert(cache_info->signature == MagickSignature);
2360 assert(id < (int) cache_info->number_threads);
2361 GetPixelInfo(image,pixel);
2362 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2363 cache_info->nexus_info[id],exception);
2364 if (p == (const Quantum *) NULL)
2365 return(MagickFalse);
2366 GetPixelInfoPixel(image,p,pixel);
2371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2375 + G e t P i x e l C a c h e C o l o r s p a c e %
2379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2381 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2383 % The format of the GetPixelCacheColorspace() method is:
2385 % Colorspace GetPixelCacheColorspace(Cache cache)
2387 % A description of each parameter follows:
2389 % o cache: the pixel cache.
2392 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2397 assert(cache != (Cache) NULL);
2398 cache_info=(CacheInfo *) cache;
2399 assert(cache_info->signature == MagickSignature);
2400 if (cache_info->debug != MagickFalse)
2401 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2402 cache_info->filename);
2403 return(cache_info->colorspace);
2407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2411 + G e t P i x e l C a c h e M e t h o d s %
2415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2417 % GetPixelCacheMethods() initializes the CacheMethods structure.
2419 % The format of the GetPixelCacheMethods() method is:
2421 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2423 % A description of each parameter follows:
2425 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2428 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2430 assert(cache_methods != (CacheMethods *) NULL);
2431 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2432 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2433 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2434 cache_methods->get_virtual_metacontent_from_handler=
2435 GetVirtualMetacontentFromCache;
2436 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2437 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2438 cache_methods->get_authentic_metacontent_from_handler=
2439 GetAuthenticMetacontentFromCache;
2440 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2441 cache_methods->get_one_authentic_pixel_from_handler=
2442 GetOneAuthenticPixelFromCache;
2443 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2444 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2445 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2453 + G e t P i x e l C a c h e N e x u s E x t e n t %
2457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2459 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2460 % corresponding with the last call to SetPixelCacheNexusPixels() or
2461 % GetPixelCacheNexusPixels().
2463 % The format of the GetPixelCacheNexusExtent() method is:
2465 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2466 % NexusInfo *nexus_info)
2468 % A description of each parameter follows:
2470 % o nexus_info: the nexus info.
2473 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2474 NexusInfo *nexus_info)
2482 assert(cache != NULL);
2483 cache_info=(CacheInfo *) cache;
2484 assert(cache_info->signature == MagickSignature);
2485 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2487 return((MagickSizeType) cache_info->columns*cache_info->rows);
2492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2496 + 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 %
2500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2502 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2505 % The format of the GetPixelCacheNexusMetacontent() method is:
2507 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2508 % NexusInfo *nexus_info)
2510 % A description of each parameter follows:
2512 % o cache: the pixel cache.
2514 % o nexus_info: the cache nexus to return the meta-content.
2517 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2518 NexusInfo *nexus_info)
2523 assert(cache != NULL);
2524 cache_info=(CacheInfo *) cache;
2525 assert(cache_info->signature == MagickSignature);
2526 if (cache_info->storage_class == UndefinedClass)
2527 return((void *) NULL);
2528 return(nexus_info->metacontent);
2532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2536 + G e t P i x e l C a c h e N e x u s P i x e l s %
2540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2542 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2545 % The format of the GetPixelCacheNexusPixels() method is:
2547 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2548 % NexusInfo *nexus_info)
2550 % A description of each parameter follows:
2552 % o cache: the pixel cache.
2554 % o nexus_info: the cache nexus to return the pixels.
2557 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2558 NexusInfo *nexus_info)
2563 assert(cache != NULL);
2564 cache_info=(CacheInfo *) cache;
2565 assert(cache_info->signature == MagickSignature);
2566 if (cache_info->storage_class == UndefinedClass)
2567 return((Quantum *) NULL);
2568 return(nexus_info->pixels);
2572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2576 + G e t P i x e l C a c h e P i x e l s %
2580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2582 % GetPixelCachePixels() returns the pixels associated with the specified image.
2584 % The format of the GetPixelCachePixels() method is:
2586 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2587 % ExceptionInfo *exception)
2589 % A description of each parameter follows:
2591 % o image: the image.
2593 % o length: the pixel cache length.
2595 % o exception: return any errors or warnings in this structure.
2598 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2599 ExceptionInfo *exception)
2604 assert(image != (const Image *) NULL);
2605 assert(image->signature == MagickSignature);
2606 assert(image->cache != (Cache) NULL);
2607 assert(length != (MagickSizeType *) NULL);
2608 assert(exception != (ExceptionInfo *) NULL);
2609 assert(exception->signature == MagickSignature);
2610 cache_info=(CacheInfo *) image->cache;
2611 assert(cache_info->signature == MagickSignature);
2613 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2614 return((void *) NULL);
2615 *length=cache_info->length;
2616 return((void *) cache_info->pixels);
2620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2624 + 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 %
2628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2630 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2632 % The format of the GetPixelCacheStorageClass() method is:
2634 % ClassType GetPixelCacheStorageClass(Cache cache)
2636 % A description of each parameter follows:
2638 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2640 % o cache: the pixel cache.
2643 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2648 assert(cache != (Cache) NULL);
2649 cache_info=(CacheInfo *) cache;
2650 assert(cache_info->signature == MagickSignature);
2651 if (cache_info->debug != MagickFalse)
2652 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2653 cache_info->filename);
2654 return(cache_info->storage_class);
2658 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2662 + G e t P i x e l C a c h e T i l e S i z e %
2666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668 % GetPixelCacheTileSize() returns the pixel cache tile size.
2670 % The format of the GetPixelCacheTileSize() method is:
2672 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2675 % A description of each parameter follows:
2677 % o image: the image.
2679 % o width: the optimize cache tile width in pixels.
2681 % o height: the optimize cache tile height in pixels.
2684 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2690 assert(image != (Image *) NULL);
2691 assert(image->signature == MagickSignature);
2692 if (image->debug != MagickFalse)
2693 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2694 cache_info=(CacheInfo *) image->cache;
2695 assert(cache_info->signature == MagickSignature);
2696 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2697 if (GetImagePixelCacheType(image) == DiskCache)
2698 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2707 + 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 %
2711 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2713 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2714 % pixel cache. A virtual pixel is any pixel access that is outside the
2715 % boundaries of the image cache.
2717 % The format of the GetPixelCacheVirtualMethod() method is:
2719 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2721 % A description of each parameter follows:
2723 % o image: the image.
2726 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2731 assert(image != (Image *) NULL);
2732 assert(image->signature == MagickSignature);
2733 assert(image->cache != (Cache) NULL);
2734 cache_info=(CacheInfo *) image->cache;
2735 assert(cache_info->signature == MagickSignature);
2736 return(cache_info->virtual_pixel_method);
2740 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2744 + 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 %
2748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2750 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2751 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2753 % The format of the GetVirtualMetacontentFromCache() method is:
2755 % void *GetVirtualMetacontentFromCache(const Image *image)
2757 % A description of each parameter follows:
2759 % o image: the image.
2762 static const void *GetVirtualMetacontentFromCache(const Image *image)
2768 id = GetOpenMPThreadId();
2773 assert(image != (const Image *) NULL);
2774 assert(image->signature == MagickSignature);
2775 assert(image->cache != (Cache) NULL);
2776 cache_info=(CacheInfo *) image->cache;
2777 assert(cache_info->signature == MagickSignature);
2778 assert(id < (int) cache_info->number_threads);
2779 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2780 cache_info->nexus_info[id]);
2781 return(metacontent);
2785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2789 + 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 %
2793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2795 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2798 % The format of the GetVirtualMetacontentFromNexus() method is:
2800 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2801 % NexusInfo *nexus_info)
2803 % A description of each parameter follows:
2805 % o cache: the pixel cache.
2807 % o nexus_info: the cache nexus to return the meta-content.
2810 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2811 NexusInfo *nexus_info)
2816 assert(cache != (Cache) NULL);
2817 cache_info=(CacheInfo *) cache;
2818 assert(cache_info->signature == MagickSignature);
2819 if (cache_info->storage_class == UndefinedClass)
2820 return((void *) NULL);
2821 return(nexus_info->metacontent);
2825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2829 % G e t V i r t u a l M e t a c o n t e n t %
2833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2835 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2836 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2837 % returned if the meta-content are not available.
2839 % The format of the GetVirtualMetacontent() method is:
2841 % const void *GetVirtualMetacontent(const Image *image)
2843 % A description of each parameter follows:
2845 % o image: the image.
2848 MagickExport const void *GetVirtualMetacontent(const Image *image)
2854 id = GetOpenMPThreadId();
2859 assert(image != (const Image *) NULL);
2860 assert(image->signature == MagickSignature);
2861 assert(image->cache != (Cache) NULL);
2862 cache_info=(CacheInfo *) image->cache;
2863 assert(cache_info->signature == MagickSignature);
2864 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2865 if (metacontent != (void *) NULL)
2866 return(metacontent);
2867 assert(id < (int) cache_info->number_threads);
2868 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2869 cache_info->nexus_info[id]);
2870 return(metacontent);
2874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2878 + 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 %
2882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2885 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2886 % is returned if the pixels are transferred, otherwise a NULL is returned.
2888 % The format of the GetVirtualPixelsFromNexus() method is:
2890 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2891 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2892 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2893 % ExceptionInfo *exception)
2895 % A description of each parameter follows:
2897 % o image: the image.
2899 % o virtual_pixel_method: the virtual pixel method.
2901 % o x,y,columns,rows: These values define the perimeter of a region of
2904 % o nexus_info: the cache nexus to acquire.
2906 % o exception: return any errors or warnings in this structure.
2913 0, 48, 12, 60, 3, 51, 15, 63,
2914 32, 16, 44, 28, 35, 19, 47, 31,
2915 8, 56, 4, 52, 11, 59, 7, 55,
2916 40, 24, 36, 20, 43, 27, 39, 23,
2917 2, 50, 14, 62, 1, 49, 13, 61,
2918 34, 18, 46, 30, 33, 17, 45, 29,
2919 10, 58, 6, 54, 9, 57, 5, 53,
2920 42, 26, 38, 22, 41, 25, 37, 21
2923 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2928 index=x+DitherMatrix[x & 0x07]-32L;
2931 if (index >= (ssize_t) columns)
2932 return((ssize_t) columns-1L);
2936 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2941 index=y+DitherMatrix[y & 0x07]-32L;
2944 if (index >= (ssize_t) rows)
2945 return((ssize_t) rows-1L);
2949 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2953 if (x >= (ssize_t) columns)
2954 return((ssize_t) (columns-1));
2958 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2962 if (y >= (ssize_t) rows)
2963 return((ssize_t) (rows-1));
2967 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2969 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2972 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2974 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2977 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2978 const size_t extent)
2984 Compute the remainder of dividing offset by extent. It returns not only
2985 the quotient (tile the offset falls in) but also the positive remainer
2986 within that tile such that 0 <= remainder < extent. This method is
2987 essentially a ldiv() using a floored modulo division rather than the
2988 normal default truncated modulo division.
2990 modulo.quotient=offset/(ssize_t) extent;
2993 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2997 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2998 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2999 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3000 ExceptionInfo *exception)
3017 virtual_pixel[CompositePixelChannel];
3022 register const Quantum
3035 register unsigned char
3042 *virtual_metacontent;
3047 assert(image != (const Image *) NULL);
3048 assert(image->signature == MagickSignature);
3049 assert(image->cache != (Cache) NULL);
3050 cache_info=(CacheInfo *) image->cache;
3051 assert(cache_info->signature == MagickSignature);
3052 if (cache_info->type == UndefinedCache)
3053 return((const Quantum *) NULL);
3056 region.width=columns;
3058 pixels=SetPixelCacheNexusPixels(image,ReadMode,®ion,nexus_info,exception);
3059 if (pixels == (Quantum *) NULL)
3060 return((const Quantum *) NULL);
3062 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3063 nexus_info->region.x;
3064 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3065 nexus_info->region.width-1L;
3066 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3067 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3068 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3069 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3075 Pixel request is inside cache extents.
3077 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3079 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3080 if (status == MagickFalse)
3081 return((const Quantum *) NULL);
3082 if (cache_info->metacontent_extent != 0)
3084 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3085 if (status == MagickFalse)
3086 return((const Quantum *) NULL);
3091 Pixel request is outside cache extents.
3093 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3094 virtual_nexus=AcquirePixelCacheNexus(1);
3095 if (virtual_nexus == (NexusInfo **) NULL)
3097 if (virtual_nexus != (NexusInfo **) NULL)
3098 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3099 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3100 "UnableToGetCacheNexus","`%s'",image->filename);
3101 return((const Quantum *) NULL);
3103 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3104 sizeof(*virtual_pixel));
3105 virtual_metacontent=(void *) NULL;
3106 switch (virtual_pixel_method)
3108 case BackgroundVirtualPixelMethod:
3109 case BlackVirtualPixelMethod:
3110 case GrayVirtualPixelMethod:
3111 case TransparentVirtualPixelMethod:
3112 case MaskVirtualPixelMethod:
3113 case WhiteVirtualPixelMethod:
3114 case EdgeVirtualPixelMethod:
3115 case CheckerTileVirtualPixelMethod:
3116 case HorizontalTileVirtualPixelMethod:
3117 case VerticalTileVirtualPixelMethod:
3119 if (cache_info->metacontent_extent != 0)
3122 Acquire a metacontent buffer.
3124 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3125 cache_info->metacontent_extent);
3126 if (virtual_metacontent == (void *) NULL)
3128 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3129 (void) ThrowMagickException(exception,GetMagickModule(),
3130 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3131 return((const Quantum *) NULL);
3133 (void) ResetMagickMemory(virtual_metacontent,0,
3134 cache_info->metacontent_extent);
3136 switch (virtual_pixel_method)
3138 case BlackVirtualPixelMethod:
3140 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3141 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3142 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3145 case GrayVirtualPixelMethod:
3147 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3148 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3150 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3153 case TransparentVirtualPixelMethod:
3155 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3156 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3157 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3160 case MaskVirtualPixelMethod:
3161 case WhiteVirtualPixelMethod:
3163 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3164 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3165 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3170 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3172 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3174 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3176 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3178 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3188 for (v=0; v < (ssize_t) rows; v++)
3190 for (u=0; u < (ssize_t) columns; u+=length)
3192 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3193 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3194 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3202 Transfer a single pixel.
3204 length=(MagickSizeType) 1;
3205 switch (virtual_pixel_method)
3209 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3210 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3211 1UL,1UL,*virtual_nexus,exception);
3212 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3215 case RandomVirtualPixelMethod:
3217 if (cache_info->random_info == (RandomInfo *) NULL)
3218 cache_info->random_info=AcquireRandomInfo();
3219 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3220 RandomX(cache_info->random_info,cache_info->columns),
3221 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3222 *virtual_nexus,exception);
3223 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3226 case DitherVirtualPixelMethod:
3228 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3229 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3230 1UL,1UL,*virtual_nexus,exception);
3231 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3234 case TileVirtualPixelMethod:
3236 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3237 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3238 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3239 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3241 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3244 case MirrorVirtualPixelMethod:
3246 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3247 if ((x_modulo.quotient & 0x01) == 1L)
3248 x_modulo.remainder=(ssize_t) cache_info->columns-
3249 x_modulo.remainder-1L;
3250 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3251 if ((y_modulo.quotient & 0x01) == 1L)
3252 y_modulo.remainder=(ssize_t) cache_info->rows-
3253 y_modulo.remainder-1L;
3254 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3255 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3257 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3260 case HorizontalTileEdgeVirtualPixelMethod:
3262 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3263 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3264 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3265 *virtual_nexus,exception);
3266 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3269 case VerticalTileEdgeVirtualPixelMethod:
3271 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3272 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3273 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3274 *virtual_nexus,exception);
3275 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3278 case BackgroundVirtualPixelMethod:
3279 case BlackVirtualPixelMethod:
3280 case GrayVirtualPixelMethod:
3281 case TransparentVirtualPixelMethod:
3282 case MaskVirtualPixelMethod:
3283 case WhiteVirtualPixelMethod:
3286 r=virtual_metacontent;
3289 case EdgeVirtualPixelMethod:
3290 case CheckerTileVirtualPixelMethod:
3292 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3293 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3294 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3297 r=virtual_metacontent;
3300 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3301 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3303 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3306 case HorizontalTileVirtualPixelMethod:
3308 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3311 r=virtual_metacontent;
3314 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3315 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3316 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3317 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3319 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3322 case VerticalTileVirtualPixelMethod:
3324 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3327 r=virtual_metacontent;
3330 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3331 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3332 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3333 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3335 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3339 if (p == (const Quantum *) NULL)
3341 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3343 q+=cache_info->number_channels;
3344 if ((s != (void *) NULL) && (r != (const void *) NULL))
3346 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3347 s+=cache_info->metacontent_extent;
3352 Transfer a run of pixels.
3354 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3355 length,1UL,*virtual_nexus,exception);
3356 if (p == (const Quantum *) NULL)
3358 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3359 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3360 q+=length*cache_info->number_channels;
3361 if ((r != (void *) NULL) && (s != (const void *) NULL))
3363 (void) memcpy(s,r,(size_t) length);
3364 s+=length*cache_info->metacontent_extent;
3371 if (virtual_metacontent != (void *) NULL)
3372 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3373 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3382 + G e t V i r t u a l P i x e l C a c h e %
3386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3388 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3389 % cache as defined by the geometry parameters. A pointer to the pixels
3390 % is returned if the pixels are transferred, otherwise a NULL is returned.
3392 % The format of the GetVirtualPixelCache() method is:
3394 % const Quantum *GetVirtualPixelCache(const Image *image,
3395 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3396 % const ssize_t y,const size_t columns,const size_t rows,
3397 % ExceptionInfo *exception)
3399 % A description of each parameter follows:
3401 % o image: the image.
3403 % o virtual_pixel_method: the virtual pixel method.
3405 % o x,y,columns,rows: These values define the perimeter of a region of
3408 % o exception: return any errors or warnings in this structure.
3411 static const Quantum *GetVirtualPixelCache(const Image *image,
3412 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3413 const size_t columns,const size_t rows,ExceptionInfo *exception)
3419 id = GetOpenMPThreadId();
3424 assert(image != (const Image *) NULL);
3425 assert(image->signature == MagickSignature);
3426 assert(image->cache != (Cache) NULL);
3427 cache_info=(CacheInfo *) image->cache;
3428 assert(cache_info->signature == MagickSignature);
3429 assert(id < (int) cache_info->number_threads);
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3431 cache_info->nexus_info[id],exception);
3436 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3440 % G e t V i r t u a l P i x e l Q u e u e %
3444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3446 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3447 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3449 % The format of the GetVirtualPixelQueue() method is:
3451 % const Quantum *GetVirtualPixelQueue(const Image image)
3453 % A description of each parameter follows:
3455 % o image: the image.
3458 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3464 id = GetOpenMPThreadId();
3466 assert(image != (const Image *) NULL);
3467 assert(image->signature == MagickSignature);
3468 assert(image->cache != (Cache) NULL);
3469 cache_info=(CacheInfo *) image->cache;
3470 assert(cache_info->signature == MagickSignature);
3471 if (cache_info->methods.get_virtual_pixels_handler !=
3472 (GetVirtualPixelsHandler) NULL)
3473 return(cache_info->methods.get_virtual_pixels_handler(image));
3474 assert(id < (int) cache_info->number_threads);
3475 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3483 % G e t V i r t u a l P i x e l s %
3487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3489 % GetVirtualPixels() returns an immutable pixel region. If the
3490 % region is successfully accessed, a pointer to it is returned, otherwise
3491 % NULL is returned. The returned pointer may point to a temporary working
3492 % copy of the pixels or it may point to the original pixels in memory.
3493 % Performance is maximized if the selected region is part of one row, or one
3494 % or more full rows, since there is opportunity to access the pixels in-place
3495 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3496 % returned pointer must *never* be deallocated by the user.
3498 % Pixels accessed via the returned pointer represent a simple array of type
3499 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3500 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3501 % access the meta-content (of type void) corresponding to the the
3504 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3506 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3507 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3508 % GetCacheViewAuthenticPixels() instead.
3510 % The format of the GetVirtualPixels() method is:
3512 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3513 % const ssize_t y,const size_t columns,const size_t rows,
3514 % ExceptionInfo *exception)
3516 % A description of each parameter follows:
3518 % o image: the image.
3520 % o x,y,columns,rows: These values define the perimeter of a region of
3523 % o exception: return any errors or warnings in this structure.
3526 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3527 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3528 ExceptionInfo *exception)
3534 id = GetOpenMPThreadId();
3539 assert(image != (const Image *) NULL);
3540 assert(image->signature == MagickSignature);
3541 assert(image->cache != (Cache) NULL);
3542 cache_info=(CacheInfo *) image->cache;
3543 assert(cache_info->signature == MagickSignature);
3544 if (cache_info->methods.get_virtual_pixel_handler !=
3545 (GetVirtualPixelHandler) NULL)
3546 return(cache_info->methods.get_virtual_pixel_handler(image,
3547 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3548 assert(id < (int) cache_info->number_threads);
3549 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3550 columns,rows,cache_info->nexus_info[id],exception);
3555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3559 + 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 %
3563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3565 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3566 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3568 % The format of the GetVirtualPixelsCache() method is:
3570 % Quantum *GetVirtualPixelsCache(const Image *image)
3572 % A description of each parameter follows:
3574 % o image: the image.
3577 static const Quantum *GetVirtualPixelsCache(const Image *image)
3583 id = GetOpenMPThreadId();
3585 assert(image != (const Image *) NULL);
3586 assert(image->signature == MagickSignature);
3587 assert(image->cache != (Cache) NULL);
3588 cache_info=(CacheInfo *) image->cache;
3589 assert(cache_info->signature == MagickSignature);
3590 assert(id < (int) cache_info->number_threads);
3591 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3599 + G e t V i r t u a l P i x e l s N e x u s %
3603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3608 % The format of the GetVirtualPixelsNexus() method is:
3610 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3611 % NexusInfo *nexus_info)
3613 % A description of each parameter follows:
3615 % o cache: the pixel cache.
3617 % o nexus_info: the cache nexus to return the colormap pixels.
3620 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3621 NexusInfo *nexus_info)
3626 assert(cache != (Cache) NULL);
3627 cache_info=(CacheInfo *) cache;
3628 assert(cache_info->signature == MagickSignature);
3629 if (cache_info->storage_class == UndefinedClass)
3630 return((Quantum *) NULL);
3631 return((const Quantum *) nexus_info->pixels);
3635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3639 + O p e n P i x e l C a c h e %
3643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3645 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3646 % dimensions, allocating space for the image pixels and optionally the
3647 % metacontent, and memory mapping the cache if it is disk based. The cache
3648 % nexus array is initialized as well.
3650 % The format of the OpenPixelCache() method is:
3652 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3653 % ExceptionInfo *exception)
3655 % A description of each parameter follows:
3657 % o image: the image.
3659 % o mode: ReadMode, WriteMode, or IOMode.
3661 % o exception: return any errors or warnings in this structure.
3665 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3667 cache_info->mapped=MagickFalse;
3668 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3669 (size_t) cache_info->length));
3670 if (cache_info->pixels == (Quantum *) NULL)
3672 cache_info->mapped=MagickTrue;
3673 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3674 cache_info->length);
3678 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3688 cache_info=(CacheInfo *) image->cache;
3689 if (image->debug != MagickFalse)
3692 format[MaxTextExtent],
3693 message[MaxTextExtent];
3695 (void) FormatMagickSize(length,MagickFalse,format);
3696 (void) FormatLocaleString(message,MaxTextExtent,
3697 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3698 cache_info->cache_filename,cache_info->file,format);
3699 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3701 if (length != (MagickSizeType) ((MagickOffsetType) length))
3702 return(MagickFalse);
3703 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3705 return(MagickFalse);
3706 if ((MagickSizeType) offset >= length)
3708 extent=(MagickOffsetType) length-1;
3709 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3710 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3711 if (cache_info->synchronize != MagickFalse)
3716 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3718 return(MagickFalse);
3721 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3724 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3725 ExceptionInfo *exception)
3732 format[MaxTextExtent],
3733 message[MaxTextExtent];
3749 assert(image != (const Image *) NULL);
3750 assert(image->signature == MagickSignature);
3751 assert(image->cache != (Cache) NULL);
3752 if (image->debug != MagickFalse)
3753 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3754 if ((image->columns == 0) || (image->rows == 0))
3755 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3756 cache_info=(CacheInfo *) image->cache;
3757 assert(cache_info->signature == MagickSignature);
3758 source_info=(*cache_info);
3759 source_info.file=(-1);
3760 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3761 image->filename,(double) GetImageIndexInList(image));
3762 cache_info->storage_class=image->storage_class;
3763 cache_info->colorspace=image->colorspace;
3764 cache_info->alpha_trait=image->alpha_trait;
3765 cache_info->mask=image->mask;
3766 cache_info->rows=image->rows;
3767 cache_info->columns=image->columns;
3768 InitializePixelChannelMap(image);
3769 cache_info->number_channels=GetPixelChannels(image);
3770 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3771 sizeof(*image->channel_map));
3772 cache_info->metacontent_extent=image->metacontent_extent;
3773 cache_info->mode=mode;
3774 if (image->ping != MagickFalse)
3776 cache_info->type=PingCache;
3777 cache_info->pixels=(Quantum *) NULL;
3778 cache_info->metacontent=(void *) NULL;
3779 cache_info->length=0;
3782 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3783 packet_size=cache_info->number_channels*sizeof(Quantum);
3784 if (image->metacontent_extent != 0)
3785 packet_size+=cache_info->metacontent_extent;
3786 length=number_pixels*packet_size;
3787 columns=(size_t) (length/cache_info->rows/packet_size);
3788 if (cache_info->columns != columns)
3789 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3791 cache_info->length=length;
3792 status=AcquireMagickResource(AreaResource,cache_info->length);
3793 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3794 cache_info->metacontent_extent);
3795 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3797 status=AcquireMagickResource(MemoryResource,cache_info->length);
3798 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3799 (cache_info->type == MemoryCache))
3801 AllocatePixelCachePixels(cache_info);
3802 if (cache_info->pixels == (Quantum *) NULL)
3803 cache_info->pixels=source_info.pixels;
3807 Create memory pixel cache.
3810 cache_info->type=MemoryCache;
3811 cache_info->metacontent=(void *) NULL;
3812 if (cache_info->metacontent_extent != 0)
3813 cache_info->metacontent=(void *) (cache_info->pixels+
3814 number_pixels*cache_info->number_channels);
3815 if ((source_info.storage_class != UndefinedClass) &&
3818 status=ClonePixelCachePixels(cache_info,&source_info,
3820 RelinquishPixelCachePixels(&source_info);
3822 if (image->debug != MagickFalse)
3824 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3825 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3827 (void) FormatLocaleString(message,MaxTextExtent,
3828 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3829 cache_info->filename,cache_info->mapped != MagickFalse ?
3830 "Anonymous" : "Heap",type,(double) cache_info->columns,
3831 (double) cache_info->rows,(double)
3832 cache_info->number_channels,format);
3833 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3839 RelinquishMagickResource(MemoryResource,cache_info->length);
3842 Create pixel cache on disk.
3844 status=AcquireMagickResource(DiskResource,cache_info->length);
3845 if (status == MagickFalse)
3847 cache_info->server_info=AcquireDistributeCacheInfo(exception);
3848 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
3850 status=OpenDistributePixelCache(cache_info->server_info,image);
3851 if (status != MagickFalse)
3853 cache_info->type=DistributedCache;
3854 if ((source_info.storage_class != UndefinedClass) &&
3857 status=ClonePixelCachePixels(cache_info,&source_info,
3859 RelinquishPixelCachePixels(&source_info);
3861 (void) FormatLocaleString(cache_info->cache_filename,
3862 MaxTextExtent,"%s:%d",
3863 GetDistributeCacheHostname(cache_info->server_info),
3864 GetDistributeCachePort(cache_info->server_info));
3865 if (image->debug != MagickFalse)
3867 (void) FormatMagickSize(cache_info->length,MagickFalse,
3869 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3871 (void) FormatLocaleString(message,MaxTextExtent,
3872 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3873 cache_info->filename,cache_info->cache_filename,
3874 GetDistributeCacheFile(cache_info->server_info),type,
3875 (double) cache_info->columns,(double) cache_info->rows,
3876 (double) cache_info->number_channels,format);
3877 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3883 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3884 "CacheResourcesExhausted","`%s'",image->filename);
3885 return(MagickFalse);
3887 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3889 (void) ClosePixelCacheOnDisk(cache_info);
3890 *cache_info->cache_filename='\0';
3892 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3894 RelinquishMagickResource(DiskResource,cache_info->length);
3895 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3897 return(MagickFalse);
3899 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3900 cache_info->length);
3901 if (status == MagickFalse)
3903 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3905 return(MagickFalse);
3907 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3908 cache_info->metacontent_extent);
3909 if (length != (MagickSizeType) ((size_t) length))
3910 cache_info->type=DiskCache;
3913 status=AcquireMagickResource(MapResource,cache_info->length);
3914 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3915 (cache_info->type != MemoryCache))
3916 cache_info->type=DiskCache;
3919 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3920 cache_info->offset,(size_t) cache_info->length);
3921 if (cache_info->pixels == (Quantum *) NULL)
3923 cache_info->type=DiskCache;
3924 cache_info->pixels=source_info.pixels;
3929 Create file-backed memory-mapped pixel cache.
3932 (void) ClosePixelCacheOnDisk(cache_info);
3933 cache_info->type=MapCache;
3934 cache_info->mapped=MagickTrue;
3935 cache_info->metacontent=(void *) NULL;
3936 if (cache_info->metacontent_extent != 0)
3937 cache_info->metacontent=(void *) (cache_info->pixels+
3938 number_pixels*cache_info->number_channels);
3939 if ((source_info.storage_class != UndefinedClass) &&
3942 status=ClonePixelCachePixels(cache_info,&source_info,
3944 RelinquishPixelCachePixels(&source_info);
3946 if (image->debug != MagickFalse)
3948 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3949 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3951 (void) FormatLocaleString(message,MaxTextExtent,
3952 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3953 cache_info->filename,cache_info->cache_filename,
3954 cache_info->file,type,(double) cache_info->columns,(double)
3955 cache_info->rows,(double) cache_info->number_channels,
3957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3963 RelinquishMagickResource(MapResource,cache_info->length);
3966 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3968 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3969 RelinquishPixelCachePixels(&source_info);
3971 if (image->debug != MagickFalse)
3973 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3974 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3976 (void) FormatLocaleString(message,MaxTextExtent,
3977 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3978 cache_info->cache_filename,cache_info->file,type,(double)
3979 cache_info->columns,(double) cache_info->rows,(double)
3980 cache_info->number_channels,format);
3981 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3991 + P e r s i s t P i x e l C a c h e %
3995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3997 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3998 % persistent pixel cache is one that resides on disk and is not destroyed
3999 % when the program exits.
4001 % The format of the PersistPixelCache() method is:
4003 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4004 % const MagickBooleanType attach,MagickOffsetType *offset,
4005 % ExceptionInfo *exception)
4007 % A description of each parameter follows:
4009 % o image: the image.
4011 % o filename: the persistent pixel cache filename.
4013 % o attach: A value other than zero initializes the persistent pixel cache.
4015 % o initialize: A value other than zero initializes the persistent pixel
4018 % o offset: the offset in the persistent cache to store pixels.
4020 % o exception: return any errors or warnings in this structure.
4023 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4024 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4025 ExceptionInfo *exception)
4040 assert(image != (Image *) NULL);
4041 assert(image->signature == MagickSignature);
4042 if (image->debug != MagickFalse)
4043 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4044 assert(image->cache != (void *) NULL);
4045 assert(filename != (const char *) NULL);
4046 assert(offset != (MagickOffsetType *) NULL);
4047 page_size=GetMagickPageSize();
4048 cache_info=(CacheInfo *) image->cache;
4049 assert(cache_info->signature == MagickSignature);
4050 if (attach != MagickFalse)
4053 Attach existing persistent pixel cache.
4055 if (image->debug != MagickFalse)
4056 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4057 "attach persistent cache");
4058 (void) CopyMagickString(cache_info->cache_filename,filename,
4060 cache_info->type=DiskCache;
4061 cache_info->offset=(*offset);
4062 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4063 return(MagickFalse);
4064 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4067 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4068 (cache_info->reference_count == 1))
4070 LockSemaphoreInfo(cache_info->semaphore);
4071 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4072 (cache_info->reference_count == 1))
4078 Usurp existing persistent pixel cache.
4080 status=rename_utf8(cache_info->cache_filename,filename);
4083 (void) CopyMagickString(cache_info->cache_filename,filename,
4085 *offset+=cache_info->length+page_size-(cache_info->length %
4087 UnlockSemaphoreInfo(cache_info->semaphore);
4088 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4089 if (image->debug != MagickFalse)
4090 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4091 "Usurp resident persistent cache");
4095 UnlockSemaphoreInfo(cache_info->semaphore);
4098 Clone persistent pixel cache.
4100 clone_image=(*image);
4101 clone_info=(CacheInfo *) clone_image.cache;
4102 image->cache=ClonePixelCache(cache_info);
4103 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4104 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4105 cache_info->type=DiskCache;
4106 cache_info->offset=(*offset);
4107 cache_info=(CacheInfo *) image->cache;
4108 status=OpenPixelCache(image,IOMode,exception);
4109 if (status != MagickFalse)
4110 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4111 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4112 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4121 + 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 %
4125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4127 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4128 % defined by the region rectangle and returns a pointer to the region. This
4129 % region is subsequently transferred from the pixel cache with
4130 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4131 % pixels are transferred, otherwise a NULL is returned.
4133 % The format of the QueueAuthenticPixelCacheNexus() method is:
4135 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4136 % const ssize_t y,const size_t columns,const size_t rows,
4137 % const MagickBooleanType clone,NexusInfo *nexus_info,
4138 % ExceptionInfo *exception)
4140 % A description of each parameter follows:
4142 % o image: the image.
4144 % o x,y,columns,rows: These values define the perimeter of a region of
4147 % o nexus_info: the cache nexus to set.
4149 % o clone: clone the pixel cache.
4151 % o exception: return any errors or warnings in this structure.
4154 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4155 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4156 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4171 Validate pixel cache geometry.
4173 assert(image != (const Image *) NULL);
4174 assert(image->signature == MagickSignature);
4175 assert(image->cache != (Cache) NULL);
4176 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4177 if (cache_info == (Cache) NULL)
4178 return((Quantum *) NULL);
4179 assert(cache_info->signature == MagickSignature);
4180 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4182 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4183 "NoPixelsDefinedInCache","`%s'",image->filename);
4184 return((Quantum *) NULL);
4186 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4187 (y >= (ssize_t) cache_info->rows))
4189 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4190 "PixelsAreNotAuthentic","`%s'",image->filename);
4191 return((Quantum *) NULL);
4193 offset=(MagickOffsetType) y*cache_info->columns+x;
4195 return((Quantum *) NULL);
4196 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4197 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4198 if ((MagickSizeType) offset >= number_pixels)
4199 return((Quantum *) NULL);
4205 region.width=columns;
4207 return(SetPixelCacheNexusPixels(image,WriteMode,®ion,nexus_info,exception));
4211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4215 + 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 %
4219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4221 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4222 % defined by the region rectangle and returns a pointer to the region. This
4223 % region is subsequently transferred from the pixel cache with
4224 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4225 % pixels are transferred, otherwise a NULL is returned.
4227 % The format of the QueueAuthenticPixelsCache() method is:
4229 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4230 % const ssize_t y,const size_t columns,const size_t rows,
4231 % ExceptionInfo *exception)
4233 % A description of each parameter follows:
4235 % o image: the image.
4237 % o x,y,columns,rows: These values define the perimeter of a region of
4240 % o exception: return any errors or warnings in this structure.
4243 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4244 const ssize_t y,const size_t columns,const size_t rows,
4245 ExceptionInfo *exception)
4251 id = GetOpenMPThreadId();
4256 assert(image != (const Image *) NULL);
4257 assert(image->signature == MagickSignature);
4258 assert(image->cache != (Cache) NULL);
4259 cache_info=(CacheInfo *) image->cache;
4260 assert(cache_info->signature == MagickSignature);
4261 assert(id < (int) cache_info->number_threads);
4262 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4263 cache_info->nexus_info[id],exception);
4268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4272 % Q u e u e A u t h e n t i c P i x e l s %
4276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4278 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4279 % successfully initialized a pointer to a Quantum array representing the
4280 % region is returned, otherwise NULL is returned. The returned pointer may
4281 % point to a temporary working buffer for the pixels or it may point to the
4282 % final location of the pixels in memory.
4284 % Write-only access means that any existing pixel values corresponding to
4285 % the region are ignored. This is useful if the initial image is being
4286 % created from scratch, or if the existing pixel values are to be
4287 % completely replaced without need to refer to their pre-existing values.
4288 % The application is free to read and write the pixel buffer returned by
4289 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4290 % initialize the pixel array values. Initializing pixel array values is the
4291 % application's responsibility.
4293 % Performance is maximized if the selected region is part of one row, or
4294 % one or more full rows, since then there is opportunity to access the
4295 % pixels in-place (without a copy) if the image is in memory, or in a
4296 % memory-mapped file. The returned pointer must *never* be deallocated
4299 % Pixels accessed via the returned pointer represent a simple array of type
4300 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4301 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4302 % obtain the meta-content (of type void) corresponding to the region.
4303 % Once the Quantum (and/or Quantum) array has been updated, the
4304 % changes must be saved back to the underlying image using
4305 % SyncAuthenticPixels() or they may be lost.
4307 % The format of the QueueAuthenticPixels() method is:
4309 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4310 % const ssize_t y,const size_t columns,const size_t rows,
4311 % ExceptionInfo *exception)
4313 % A description of each parameter follows:
4315 % o image: the image.
4317 % o x,y,columns,rows: These values define the perimeter of a region of
4320 % o exception: return any errors or warnings in this structure.
4323 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4324 const ssize_t y,const size_t columns,const size_t rows,
4325 ExceptionInfo *exception)
4331 id = GetOpenMPThreadId();
4336 assert(image != (Image *) NULL);
4337 assert(image->signature == MagickSignature);
4338 assert(image->cache != (Cache) NULL);
4339 cache_info=(CacheInfo *) image->cache;
4340 assert(cache_info->signature == MagickSignature);
4341 if (cache_info->methods.queue_authentic_pixels_handler !=
4342 (QueueAuthenticPixelsHandler) NULL)
4344 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4348 assert(id < (int) cache_info->number_threads);
4349 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4350 cache_info->nexus_info[id],exception);
4355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4359 + 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 %
4363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4365 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4368 % The format of the ReadPixelCacheMetacontent() method is:
4370 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4371 % NexusInfo *nexus_info,ExceptionInfo *exception)
4373 % A description of each parameter follows:
4375 % o cache_info: the pixel cache.
4377 % o nexus_info: the cache nexus to read the metacontent.
4379 % o exception: return any errors or warnings in this structure.
4382 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4383 NexusInfo *nexus_info,ExceptionInfo *exception)
4396 register unsigned char
4402 if (cache_info->metacontent_extent == 0)
4403 return(MagickFalse);
4404 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4406 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4407 nexus_info->region.x;
4408 length=(MagickSizeType) nexus_info->region.width*
4409 cache_info->metacontent_extent;
4410 rows=nexus_info->region.height;
4412 q=(unsigned char *) nexus_info->metacontent;
4413 switch (cache_info->type)
4418 register unsigned char
4422 Read meta-content from memory.
4424 if ((cache_info->columns == nexus_info->region.width) &&
4425 (extent == (MagickSizeType) ((size_t) extent)))
4430 p=(unsigned char *) cache_info->metacontent+offset*
4431 cache_info->metacontent_extent;
4432 for (y=0; y < (ssize_t) rows; y++)
4434 (void) memcpy(q,p,(size_t) length);
4435 p+=cache_info->metacontent_extent*cache_info->columns;
4436 q+=cache_info->metacontent_extent*nexus_info->region.width;
4443 Read meta content from disk.
4445 LockSemaphoreInfo(cache_info->file_semaphore);
4446 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4448 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4449 cache_info->cache_filename);
4450 UnlockSemaphoreInfo(cache_info->file_semaphore);
4451 return(MagickFalse);
4453 if ((cache_info->columns == nexus_info->region.width) &&
4454 (extent <= MagickMaxBufferExtent))
4459 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4460 for (y=0; y < (ssize_t) rows; y++)
4462 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4463 cache_info->number_channels*sizeof(Quantum)+offset*
4464 cache_info->metacontent_extent,length,(unsigned char *) q);
4465 if ((MagickSizeType) count != length)
4467 offset+=cache_info->columns;
4468 q+=cache_info->metacontent_extent*nexus_info->region.width;
4470 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4471 (void) ClosePixelCacheOnDisk(cache_info);
4472 UnlockSemaphoreInfo(cache_info->file_semaphore);
4473 if (y < (ssize_t) rows)
4475 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4476 cache_info->cache_filename);
4477 return(MagickFalse);
4481 case DistributedCache:
4487 Read metacontent from distributed cache.
4489 LockSemaphoreInfo(cache_info->file_semaphore);
4490 status=ReadDistributePixelCacheMetacontent(cache_info->server_info,
4491 &nexus_info->region,length,(unsigned char *) nexus_info->pixels);
4492 UnlockSemaphoreInfo(cache_info->file_semaphore);
4493 if (status == MagickFalse)
4495 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4496 cache_info->cache_filename);
4497 return(MagickFalse);
4504 if ((cache_info->debug != MagickFalse) &&
4505 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4506 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4507 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4508 nexus_info->region.width,(double) nexus_info->region.height,(double)
4509 nexus_info->region.x,(double) nexus_info->region.y);
4514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4518 + R e a d P i x e l C a c h e P i x e l s %
4522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4524 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4527 % The format of the ReadPixelCachePixels() method is:
4529 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4530 % NexusInfo *nexus_info,ExceptionInfo *exception)
4532 % A description of each parameter follows:
4534 % o cache_info: the pixel cache.
4536 % o nexus_info: the cache nexus to read the pixels.
4538 % o exception: return any errors or warnings in this structure.
4541 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4542 NexusInfo *nexus_info,ExceptionInfo *exception)
4561 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4563 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4564 nexus_info->region.x;
4565 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4567 rows=nexus_info->region.height;
4569 q=nexus_info->pixels;
4570 switch (cache_info->type)
4579 Read pixels from memory.
4581 if ((cache_info->columns == nexus_info->region.width) &&
4582 (extent == (MagickSizeType) ((size_t) extent)))
4587 p=cache_info->pixels+offset*cache_info->number_channels;
4588 for (y=0; y < (ssize_t) rows; y++)
4590 (void) memcpy(q,p,(size_t) length);
4591 p+=cache_info->number_channels*cache_info->columns;
4592 q+=cache_info->number_channels*nexus_info->region.width;
4599 Read pixels from disk.
4601 LockSemaphoreInfo(cache_info->file_semaphore);
4602 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4604 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4605 cache_info->cache_filename);
4606 UnlockSemaphoreInfo(cache_info->file_semaphore);
4607 return(MagickFalse);
4609 if ((cache_info->columns == nexus_info->region.width) &&
4610 (extent <= MagickMaxBufferExtent))
4615 for (y=0; y < (ssize_t) rows; y++)
4617 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4618 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4619 if ((MagickSizeType) count != length)
4621 offset+=cache_info->columns;
4622 q+=cache_info->number_channels*nexus_info->region.width;
4624 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4625 (void) ClosePixelCacheOnDisk(cache_info);
4626 UnlockSemaphoreInfo(cache_info->file_semaphore);
4627 if (y < (ssize_t) rows)
4629 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4630 cache_info->cache_filename);
4631 return(MagickFalse);
4635 case DistributedCache:
4641 Read pixels from distributed cache.
4643 LockSemaphoreInfo(cache_info->file_semaphore);
4644 status=ReadDistributePixelCachePixels(cache_info->server_info,
4645 &nexus_info->region,length,(unsigned char *) nexus_info->pixels);
4646 UnlockSemaphoreInfo(cache_info->file_semaphore);
4647 if (status == MagickFalse)
4649 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4650 cache_info->cache_filename);
4651 return(MagickFalse);
4658 if ((cache_info->debug != MagickFalse) &&
4659 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4660 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4661 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4662 nexus_info->region.width,(double) nexus_info->region.height,(double)
4663 nexus_info->region.x,(double) nexus_info->region.y);
4668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4672 + R e f e r e n c e P i x e l C a c h e %
4676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4678 % ReferencePixelCache() increments the reference count associated with the
4679 % pixel cache returning a pointer to the cache.
4681 % The format of the ReferencePixelCache method is:
4683 % Cache ReferencePixelCache(Cache cache_info)
4685 % A description of each parameter follows:
4687 % o cache_info: the pixel cache.
4690 MagickPrivate Cache ReferencePixelCache(Cache cache)
4695 assert(cache != (Cache *) NULL);
4696 cache_info=(CacheInfo *) cache;
4697 assert(cache_info->signature == MagickSignature);
4698 LockSemaphoreInfo(cache_info->semaphore);
4699 cache_info->reference_count++;
4700 UnlockSemaphoreInfo(cache_info->semaphore);
4705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4709 + S e t P i x e l C a c h e M e t h o d s %
4713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4715 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4717 % The format of the SetPixelCacheMethods() method is:
4719 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4721 % A description of each parameter follows:
4723 % o cache: the pixel cache.
4725 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4728 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4733 GetOneAuthenticPixelFromHandler
4734 get_one_authentic_pixel_from_handler;
4736 GetOneVirtualPixelFromHandler
4737 get_one_virtual_pixel_from_handler;
4740 Set cache pixel methods.
4742 assert(cache != (Cache) NULL);
4743 assert(cache_methods != (CacheMethods *) NULL);
4744 cache_info=(CacheInfo *) cache;
4745 assert(cache_info->signature == MagickSignature);
4746 if (cache_info->debug != MagickFalse)
4747 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4748 cache_info->filename);
4749 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4750 cache_info->methods.get_virtual_pixel_handler=
4751 cache_methods->get_virtual_pixel_handler;
4752 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4753 cache_info->methods.destroy_pixel_handler=
4754 cache_methods->destroy_pixel_handler;
4755 if (cache_methods->get_virtual_metacontent_from_handler !=
4756 (GetVirtualMetacontentFromHandler) NULL)
4757 cache_info->methods.get_virtual_metacontent_from_handler=
4758 cache_methods->get_virtual_metacontent_from_handler;
4759 if (cache_methods->get_authentic_pixels_handler !=
4760 (GetAuthenticPixelsHandler) NULL)
4761 cache_info->methods.get_authentic_pixels_handler=
4762 cache_methods->get_authentic_pixels_handler;
4763 if (cache_methods->queue_authentic_pixels_handler !=
4764 (QueueAuthenticPixelsHandler) NULL)
4765 cache_info->methods.queue_authentic_pixels_handler=
4766 cache_methods->queue_authentic_pixels_handler;
4767 if (cache_methods->sync_authentic_pixels_handler !=
4768 (SyncAuthenticPixelsHandler) NULL)
4769 cache_info->methods.sync_authentic_pixels_handler=
4770 cache_methods->sync_authentic_pixels_handler;
4771 if (cache_methods->get_authentic_pixels_from_handler !=
4772 (GetAuthenticPixelsFromHandler) NULL)
4773 cache_info->methods.get_authentic_pixels_from_handler=
4774 cache_methods->get_authentic_pixels_from_handler;
4775 if (cache_methods->get_authentic_metacontent_from_handler !=
4776 (GetAuthenticMetacontentFromHandler) NULL)
4777 cache_info->methods.get_authentic_metacontent_from_handler=
4778 cache_methods->get_authentic_metacontent_from_handler;
4779 get_one_virtual_pixel_from_handler=
4780 cache_info->methods.get_one_virtual_pixel_from_handler;
4781 if (get_one_virtual_pixel_from_handler !=
4782 (GetOneVirtualPixelFromHandler) NULL)
4783 cache_info->methods.get_one_virtual_pixel_from_handler=
4784 cache_methods->get_one_virtual_pixel_from_handler;
4785 get_one_authentic_pixel_from_handler=
4786 cache_methods->get_one_authentic_pixel_from_handler;
4787 if (get_one_authentic_pixel_from_handler !=
4788 (GetOneAuthenticPixelFromHandler) NULL)
4789 cache_info->methods.get_one_authentic_pixel_from_handler=
4790 cache_methods->get_one_authentic_pixel_from_handler;
4794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4798 + S e t P i x e l C a c h e N e x u s P i x e l s %
4802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4804 % SetPixelCacheNexusPixels() defines the region of the cache for the
4805 % specified cache nexus.
4807 % The format of the SetPixelCacheNexusPixels() method is:
4809 % Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4810 % const RectangleInfo *region,NexusInfo *nexus_info,
4811 % ExceptionInfo *exception)
4813 % A description of each parameter follows:
4815 % o image: the image.
4817 % o mode: ReadMode, WriteMode, or IOMode.
4819 % o region: A pointer to the RectangleInfo structure that defines the
4820 % region of this particular cache nexus.
4822 % o nexus_info: the cache nexus to set.
4824 % o exception: return any errors or warnings in this structure.
4828 static inline MagickBooleanType AcquireCacheNexusPixels(
4829 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4830 ExceptionInfo *exception)
4832 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4833 return(MagickFalse);
4834 nexus_info->mapped=MagickFalse;
4835 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4836 (size_t) nexus_info->length));
4837 if (nexus_info->cache == (Quantum *) NULL)
4839 nexus_info->mapped=MagickTrue;
4840 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4841 nexus_info->length);
4843 if (nexus_info->cache == (Quantum *) NULL)
4845 (void) ThrowMagickException(exception,GetMagickModule(),
4846 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4847 cache_info->filename);
4848 return(MagickFalse);
4853 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4856 if (mode == ReadMode)
4858 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4861 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4864 static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4865 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4877 cache_info=(CacheInfo *) image->cache;
4878 assert(cache_info->signature == MagickSignature);
4879 if (cache_info->type == UndefinedCache)
4880 return((Quantum *) NULL);
4881 nexus_info->region=(*region);
4882 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4888 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4889 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4890 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4891 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4892 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4893 ((nexus_info->region.width == cache_info->columns) ||
4894 ((nexus_info->region.width % cache_info->columns) == 0)))))
4900 Pixels are accessed directly from memory.
4902 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4903 nexus_info->region.x;
4904 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4906 nexus_info->metacontent=(void *) NULL;
4907 if (cache_info->metacontent_extent != 0)
4908 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4909 offset*cache_info->metacontent_extent;
4910 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4911 return(nexus_info->pixels);
4915 Pixels are stored in a cache region until they are synced to the cache.
4917 number_pixels=(MagickSizeType) nexus_info->region.width*
4918 nexus_info->region.height;
4919 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4920 if (cache_info->metacontent_extent != 0)
4921 length+=number_pixels*cache_info->metacontent_extent;
4922 if (nexus_info->cache == (Quantum *) NULL)
4924 nexus_info->length=length;
4925 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4926 if (status == MagickFalse)
4928 nexus_info->length=0;
4929 return((Quantum *) NULL);
4933 if (nexus_info->length != length)
4935 RelinquishCacheNexusPixels(nexus_info);
4936 nexus_info->length=length;
4937 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4938 if (status == MagickFalse)
4940 nexus_info->length=0;
4941 return((Quantum *) NULL);
4944 nexus_info->pixels=nexus_info->cache;
4945 nexus_info->metacontent=(void *) NULL;
4946 if (cache_info->metacontent_extent != 0)
4947 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4948 cache_info->number_channels);
4949 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4950 return(nexus_info->pixels);
4954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4958 % 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 %
4962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4964 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4965 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4966 % access that is outside the boundaries of the image cache.
4968 % The format of the SetPixelCacheVirtualMethod() method is:
4970 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4971 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4973 % A description of each parameter follows:
4975 % o image: the image.
4977 % o virtual_pixel_method: choose the type of virtual pixel.
4979 % o exception: return any errors or warnings in this structure.
4983 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4984 ExceptionInfo *exception)
4998 assert(image != (Image *) NULL);
4999 assert(image->signature == MagickSignature);
5000 if (image->debug != MagickFalse)
5001 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5002 assert(image->cache != (Cache) NULL);
5003 cache_info=(CacheInfo *) image->cache;
5004 assert(cache_info->signature == MagickSignature);
5005 image->alpha_trait=BlendPixelTrait;
5007 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
5008 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5009 #pragma omp parallel for schedule(static,4) shared(status) \
5010 magick_threads(image,image,1,1)
5012 for (y=0; y < (ssize_t) image->rows; y++)
5020 if (status == MagickFalse)
5022 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5023 if (q == (Quantum *) NULL)
5028 for (x=0; x < (ssize_t) image->columns; x++)
5030 SetPixelAlpha(image,alpha,q);
5031 q+=GetPixelChannels(image);
5033 status=SyncCacheViewAuthenticPixels(image_view,exception);
5035 image_view=DestroyCacheView(image_view);
5039 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5040 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5048 assert(image != (Image *) NULL);
5049 assert(image->signature == MagickSignature);
5050 if (image->debug != MagickFalse)
5051 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5052 assert(image->cache != (Cache) NULL);
5053 cache_info=(CacheInfo *) image->cache;
5054 assert(cache_info->signature == MagickSignature);
5055 method=cache_info->virtual_pixel_method;
5056 cache_info->virtual_pixel_method=virtual_pixel_method;
5057 if ((image->columns != 0) && (image->rows != 0))
5058 switch (virtual_pixel_method)
5060 case BackgroundVirtualPixelMethod:
5062 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
5063 (image->alpha_trait != BlendPixelTrait))
5064 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5065 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
5066 (IsGrayColorspace(image->colorspace) != MagickFalse))
5067 (void) TransformImageColorspace(image,RGBColorspace,exception);
5070 case TransparentVirtualPixelMethod:
5072 if (image->alpha_trait != BlendPixelTrait)
5073 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5087 + 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 %
5091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5093 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5094 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5095 % is synced, otherwise MagickFalse.
5097 % The format of the SyncAuthenticPixelCacheNexus() method is:
5099 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5100 % NexusInfo *nexus_info,ExceptionInfo *exception)
5102 % A description of each parameter follows:
5104 % o image: the image.
5106 % o nexus_info: the cache nexus to sync.
5108 % o exception: return any errors or warnings in this structure.
5111 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5112 NexusInfo *nexus_info,ExceptionInfo *exception)
5121 Transfer pixels to the cache.
5123 assert(image != (Image *) NULL);
5124 assert(image->signature == MagickSignature);
5125 if (image->cache == (Cache) NULL)
5126 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5127 cache_info=(CacheInfo *) image->cache;
5128 assert(cache_info->signature == MagickSignature);
5129 if (cache_info->type == UndefinedCache)
5130 return(MagickFalse);
5131 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5133 assert(cache_info->signature == MagickSignature);
5134 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5135 if ((cache_info->metacontent_extent != 0) &&
5136 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5137 return(MagickFalse);
5142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5146 + S y n c A u t h e n t i c P i x e l C a c h e %
5150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5152 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5153 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5154 % otherwise MagickFalse.
5156 % The format of the SyncAuthenticPixelsCache() method is:
5158 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5159 % ExceptionInfo *exception)
5161 % A description of each parameter follows:
5163 % o image: the image.
5165 % o exception: return any errors or warnings in this structure.
5168 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5169 ExceptionInfo *exception)
5175 id = GetOpenMPThreadId();
5180 assert(image != (Image *) NULL);
5181 assert(image->signature == MagickSignature);
5182 assert(image->cache != (Cache) NULL);
5183 cache_info=(CacheInfo *) image->cache;
5184 assert(cache_info->signature == MagickSignature);
5185 assert(id < (int) cache_info->number_threads);
5186 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5196 % S y n c A u t h e n t i c P i x e l s %
5200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5202 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5203 % The method returns MagickTrue if the pixel region is flushed, otherwise
5206 % The format of the SyncAuthenticPixels() method is:
5208 % MagickBooleanType SyncAuthenticPixels(Image *image,
5209 % ExceptionInfo *exception)
5211 % A description of each parameter follows:
5213 % o image: the image.
5215 % o exception: return any errors or warnings in this structure.
5218 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5219 ExceptionInfo *exception)
5225 id = GetOpenMPThreadId();
5230 assert(image != (Image *) NULL);
5231 assert(image->signature == MagickSignature);
5232 assert(image->cache != (Cache) NULL);
5233 cache_info=(CacheInfo *) image->cache;
5234 assert(cache_info->signature == MagickSignature);
5235 if (cache_info->methods.sync_authentic_pixels_handler !=
5236 (SyncAuthenticPixelsHandler) NULL)
5238 status=cache_info->methods.sync_authentic_pixels_handler(image,
5242 assert(id < (int) cache_info->number_threads);
5243 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5253 + S y n c I m a g e P i x e l C a c h e %
5257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5259 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5260 % The method returns MagickTrue if the pixel region is flushed, otherwise
5263 % The format of the SyncImagePixelCache() method is:
5265 % MagickBooleanType SyncImagePixelCache(Image *image,
5266 % ExceptionInfo *exception)
5268 % A description of each parameter follows:
5270 % o image: the image.
5272 % o exception: return any errors or warnings in this structure.
5275 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5276 ExceptionInfo *exception)
5281 assert(image != (Image *) NULL);
5282 assert(exception != (ExceptionInfo *) NULL);
5283 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5284 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5292 + 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 %
5296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5298 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5299 % of the pixel cache.
5301 % The format of the WritePixelCacheMetacontent() method is:
5303 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5304 % NexusInfo *nexus_info,ExceptionInfo *exception)
5306 % A description of each parameter follows:
5308 % o cache_info: the pixel cache.
5310 % o nexus_info: the cache nexus to write the meta-content.
5312 % o exception: return any errors or warnings in this structure.
5315 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5316 NexusInfo *nexus_info,ExceptionInfo *exception)
5326 register const unsigned char
5335 if (cache_info->metacontent_extent == 0)
5336 return(MagickFalse);
5337 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5339 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5340 nexus_info->region.x;
5341 length=(MagickSizeType) nexus_info->region.width*
5342 cache_info->metacontent_extent;
5343 rows=nexus_info->region.height;
5344 extent=(MagickSizeType) length*rows;
5345 p=(unsigned char *) nexus_info->metacontent;
5346 switch (cache_info->type)
5351 register unsigned char
5355 Write associated pixels to memory.
5357 if ((cache_info->columns == nexus_info->region.width) &&
5358 (extent == (MagickSizeType) ((size_t) extent)))
5363 q=(unsigned char *) cache_info->metacontent+offset*
5364 cache_info->metacontent_extent;
5365 for (y=0; y < (ssize_t) rows; y++)
5367 (void) memcpy(q,p,(size_t) length);
5368 p+=nexus_info->region.width*cache_info->metacontent_extent;
5369 q+=cache_info->columns*cache_info->metacontent_extent;
5376 Write associated pixels to disk.
5378 LockSemaphoreInfo(cache_info->file_semaphore);
5379 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5381 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5382 cache_info->cache_filename);
5383 UnlockSemaphoreInfo(cache_info->file_semaphore);
5384 return(MagickFalse);
5386 if ((cache_info->columns == nexus_info->region.width) &&
5387 (extent <= MagickMaxBufferExtent))
5392 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5393 for (y=0; y < (ssize_t) rows; y++)
5395 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5396 cache_info->number_channels*sizeof(Quantum)+offset*
5397 cache_info->metacontent_extent,length,(const unsigned char *) p);
5398 if ((MagickSizeType) count != length)
5400 p+=nexus_info->region.width*cache_info->metacontent_extent;
5401 offset+=cache_info->columns;
5403 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5404 (void) ClosePixelCacheOnDisk(cache_info);
5405 UnlockSemaphoreInfo(cache_info->file_semaphore);
5406 if (y < (ssize_t) rows)
5408 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5409 cache_info->cache_filename);
5410 return(MagickFalse);
5414 case DistributedCache:
5420 Write metacontent to distributed cache.
5422 LockSemaphoreInfo(cache_info->file_semaphore);
5423 status=WriteDistributePixelCacheMetacontent(cache_info->server_info,
5424 &nexus_info->region,length,(const unsigned char *)
5425 nexus_info->metacontent);
5426 UnlockSemaphoreInfo(cache_info->file_semaphore);
5427 if (status == MagickFalse)
5429 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5430 cache_info->cache_filename);
5431 return(MagickFalse);
5438 if ((cache_info->debug != MagickFalse) &&
5439 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5440 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5441 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5442 nexus_info->region.width,(double) nexus_info->region.height,(double)
5443 nexus_info->region.x,(double) nexus_info->region.y);
5448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5452 + W r i t e C a c h e P i x e l s %
5456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5458 % WritePixelCachePixels() writes image pixels to the specified region of the
5461 % The format of the WritePixelCachePixels() method is:
5463 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5464 % NexusInfo *nexus_info,ExceptionInfo *exception)
5466 % A description of each parameter follows:
5468 % o cache_info: the pixel cache.
5470 % o nexus_info: the cache nexus to write the pixels.
5472 % o exception: return any errors or warnings in this structure.
5475 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5476 NexusInfo *nexus_info,ExceptionInfo *exception)
5486 register const Quantum
5495 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5497 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5498 nexus_info->region.x;
5499 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5501 rows=nexus_info->region.height;
5503 p=nexus_info->pixels;
5504 switch (cache_info->type)
5513 Write pixels to memory.
5515 if ((cache_info->columns == nexus_info->region.width) &&
5516 (extent == (MagickSizeType) ((size_t) extent)))
5521 q=cache_info->pixels+offset*cache_info->number_channels;
5522 for (y=0; y < (ssize_t) rows; y++)
5524 (void) memcpy(q,p,(size_t) length);
5525 p+=nexus_info->region.width*cache_info->number_channels;
5526 q+=cache_info->columns*cache_info->number_channels;
5533 Write pixels to disk.
5535 LockSemaphoreInfo(cache_info->file_semaphore);
5536 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5538 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5539 cache_info->cache_filename);
5540 UnlockSemaphoreInfo(cache_info->file_semaphore);
5541 return(MagickFalse);
5543 if ((cache_info->columns == nexus_info->region.width) &&
5544 (extent <= MagickMaxBufferExtent))
5549 for (y=0; y < (ssize_t) rows; y++)
5551 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5552 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5554 if ((MagickSizeType) count != length)
5556 p+=nexus_info->region.width*cache_info->number_channels;
5557 offset+=cache_info->columns;
5559 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5560 (void) ClosePixelCacheOnDisk(cache_info);
5561 UnlockSemaphoreInfo(cache_info->file_semaphore);
5562 if (y < (ssize_t) rows)
5564 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5565 cache_info->cache_filename);
5566 return(MagickFalse);
5570 case DistributedCache:
5576 Write pixels to distributed cache.
5578 LockSemaphoreInfo(cache_info->file_semaphore);
5579 status=WriteDistributePixelCachePixels(cache_info->server_info,
5580 &nexus_info->region,length,(const unsigned char *) nexus_info->pixels);
5581 UnlockSemaphoreInfo(cache_info->file_semaphore);
5582 if (status == MagickFalse)
5584 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5585 cache_info->cache_filename);
5586 return(MagickFalse);
5593 if ((cache_info->debug != MagickFalse) &&
5594 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5595 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5596 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5597 nexus_info->region.width,(double) nexus_info->region.height,(double)
5598 nexus_info->region.x,(double) nexus_info->region.y);