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 (clone_info->type == DistributedCache))
1050 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1051 p=cache_info->channel_map;
1052 q=clone_info->channel_map;
1053 if ((cache_info->columns == clone_info->columns) &&
1054 (cache_info->rows == clone_info->rows) &&
1055 (cache_info->number_channels == clone_info->number_channels) &&
1056 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1057 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1058 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1059 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1067 + C l o n e P i x e l C a c h e M e t h o d s %
1071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1076 % The format of the ClonePixelCacheMethods() method is:
1078 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1080 % A description of each parameter follows:
1082 % o clone: Specifies a pointer to a Cache structure.
1084 % o cache: the pixel cache.
1087 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1093 assert(clone != (Cache) NULL);
1094 source_info=(CacheInfo *) clone;
1095 assert(source_info->signature == MagickSignature);
1096 if (source_info->debug != MagickFalse)
1097 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1098 source_info->filename);
1099 assert(cache != (Cache) NULL);
1100 cache_info=(CacheInfo *) cache;
1101 assert(cache_info->signature == MagickSignature);
1102 source_info->methods=cache_info->methods;
1106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1110 + D e s t r o y I m a g e P i x e l C a c h e %
1114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1116 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1118 % The format of the DestroyImagePixelCache() method is:
1120 % void DestroyImagePixelCache(Image *image)
1122 % A description of each parameter follows:
1124 % o image: the image.
1127 static void DestroyImagePixelCache(Image *image)
1129 assert(image != (Image *) NULL);
1130 assert(image->signature == MagickSignature);
1131 if (image->debug != MagickFalse)
1132 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1133 if (image->cache == (void *) NULL)
1135 image->cache=DestroyPixelCache(image->cache);
1139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1143 + D e s t r o y I m a g e P i x e l s %
1147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1149 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1151 % The format of the DestroyImagePixels() method is:
1153 % void DestroyImagePixels(Image *image)
1155 % A description of each parameter follows:
1157 % o image: the image.
1160 MagickExport void DestroyImagePixels(Image *image)
1165 assert(image != (const Image *) NULL);
1166 assert(image->signature == MagickSignature);
1167 if (image->debug != MagickFalse)
1168 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1169 assert(image->cache != (Cache) NULL);
1170 cache_info=(CacheInfo *) image->cache;
1171 assert(cache_info->signature == MagickSignature);
1172 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1174 cache_info->methods.destroy_pixel_handler(image);
1177 image->cache=DestroyPixelCache(image->cache);
1181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1185 + D e s t r o y P i x e l C a c h e %
1189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1193 % The format of the DestroyPixelCache() method is:
1195 % Cache DestroyPixelCache(Cache cache)
1197 % A description of each parameter follows:
1199 % o cache: the pixel cache.
1203 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1205 switch (cache_info->type)
1209 if (cache_info->mapped == MagickFalse)
1210 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
1211 cache_info->pixels);
1213 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1214 (size_t) cache_info->length);
1215 RelinquishMagickResource(MemoryResource,cache_info->length);
1220 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1221 cache_info->length);
1222 if (cache_info->mode != ReadMode)
1223 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1224 *cache_info->cache_filename='\0';
1225 RelinquishMagickResource(MapResource,cache_info->length);
1229 if (cache_info->file != -1)
1230 (void) ClosePixelCacheOnDisk(cache_info);
1231 if (cache_info->mode != ReadMode)
1232 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1233 *cache_info->cache_filename='\0';
1234 RelinquishMagickResource(DiskResource,cache_info->length);
1237 case DistributedCache:
1239 *cache_info->cache_filename='\0';
1240 (void) RelinquishDistributePixelCache(cache_info->server_info);
1246 cache_info->type=UndefinedCache;
1247 cache_info->mapped=MagickFalse;
1248 cache_info->metacontent=(void *) NULL;
1251 MagickPrivate Cache DestroyPixelCache(Cache cache)
1256 assert(cache != (Cache) NULL);
1257 cache_info=(CacheInfo *) cache;
1258 assert(cache_info->signature == MagickSignature);
1259 if (cache_info->debug != MagickFalse)
1260 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1261 cache_info->filename);
1262 LockSemaphoreInfo(cache_info->semaphore);
1263 cache_info->reference_count--;
1264 if (cache_info->reference_count != 0)
1266 UnlockSemaphoreInfo(cache_info->semaphore);
1267 return((Cache) NULL);
1269 UnlockSemaphoreInfo(cache_info->semaphore);
1270 if (cache_info->debug != MagickFalse)
1273 message[MaxTextExtent];
1275 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1276 cache_info->filename);
1277 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1279 RelinquishPixelCachePixels(cache_info);
1280 if (cache_info->server_info != (DistributeCacheInfo *) NULL)
1281 cache_info->server_info=DestroyDistributeCacheInfo(cache_info->server_info);
1282 if (cache_info->nexus_info != (NexusInfo **) NULL)
1283 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1284 cache_info->number_threads);
1285 if (cache_info->random_info != (RandomInfo *) NULL)
1286 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1287 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
1288 DestroySemaphoreInfo(&cache_info->file_semaphore);
1289 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1290 DestroySemaphoreInfo(&cache_info->semaphore);
1291 cache_info->signature=(~MagickSignature);
1292 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302 + D e s t r o y P i x e l C a c h e N e x u s %
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1310 % The format of the DestroyPixelCacheNexus() method is:
1312 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1313 % const size_t number_threads)
1315 % A description of each parameter follows:
1317 % o nexus_info: the nexus to destroy.
1319 % o number_threads: the number of nexus threads.
1323 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1325 if (nexus_info->mapped == MagickFalse)
1326 (void) RelinquishAlignedMemory(nexus_info->cache);
1328 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1329 nexus_info->cache=(Quantum *) NULL;
1330 nexus_info->pixels=(Quantum *) NULL;
1331 nexus_info->metacontent=(void *) NULL;
1332 nexus_info->length=0;
1333 nexus_info->mapped=MagickFalse;
1336 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1337 const size_t number_threads)
1342 assert(nexus_info != (NexusInfo **) NULL);
1343 for (i=0; i < (ssize_t) number_threads; i++)
1345 if (nexus_info[i]->cache != (Quantum *) NULL)
1346 RelinquishCacheNexusPixels(nexus_info[i]);
1347 nexus_info[i]->signature=(~MagickSignature);
1349 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1350 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359 % G e t A u t h e n t i c M e t a c o n t e n t %
1363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1366 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1367 % returned if the associated pixels are not available.
1369 % The format of the GetAuthenticMetacontent() method is:
1371 % void *GetAuthenticMetacontent(const Image *image)
1373 % A description of each parameter follows:
1375 % o image: the image.
1378 MagickExport void *GetAuthenticMetacontent(const Image *image)
1384 id = GetOpenMPThreadId();
1389 assert(image != (const Image *) NULL);
1390 assert(image->signature == MagickSignature);
1391 assert(image->cache != (Cache) NULL);
1392 cache_info=(CacheInfo *) image->cache;
1393 assert(cache_info->signature == MagickSignature);
1394 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1395 (GetAuthenticMetacontentFromHandler) NULL)
1397 metacontent=cache_info->methods.
1398 get_authentic_metacontent_from_handler(image);
1399 return(metacontent);
1401 assert(id < (int) cache_info->number_threads);
1402 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1403 cache_info->nexus_info[id]);
1404 return(metacontent);
1408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1412 + 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 %
1416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1418 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1419 % with the last call to QueueAuthenticPixelsCache() or
1420 % GetAuthenticPixelsCache().
1422 % The format of the GetAuthenticMetacontentFromCache() method is:
1424 % void *GetAuthenticMetacontentFromCache(const Image *image)
1426 % A description of each parameter follows:
1428 % o image: the image.
1431 static void *GetAuthenticMetacontentFromCache(const Image *image)
1437 id = GetOpenMPThreadId();
1442 assert(image != (const Image *) NULL);
1443 assert(image->signature == MagickSignature);
1444 assert(image->cache != (Cache) NULL);
1445 cache_info=(CacheInfo *) image->cache;
1446 assert(cache_info->signature == MagickSignature);
1447 assert(id < (int) cache_info->number_threads);
1448 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1449 cache_info->nexus_info[id]);
1450 return(metacontent);
1454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1458 + 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 %
1462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1464 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1465 % disk pixel cache as defined by the geometry parameters. A pointer to the
1466 % pixels is returned if the pixels are transferred, otherwise a NULL is
1469 % The format of the GetAuthenticPixelCacheNexus() method is:
1471 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1472 % const ssize_t y,const size_t columns,const size_t rows,
1473 % NexusInfo *nexus_info,ExceptionInfo *exception)
1475 % A description of each parameter follows:
1477 % o image: the image.
1479 % o x,y,columns,rows: These values define the perimeter of a region of
1482 % o nexus_info: the cache nexus to return.
1484 % o exception: return any errors or warnings in this structure.
1488 static inline MagickBooleanType IsPixelAuthentic(
1489 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1497 if (cache_info->type == PingCache)
1499 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1500 nexus_info->region.x;
1501 status=nexus_info->pixels == (cache_info->pixels+offset*
1502 cache_info->number_channels) ? MagickTrue : MagickFalse;
1506 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1507 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1508 NexusInfo *nexus_info,ExceptionInfo *exception)
1517 Transfer pixels from the cache.
1519 assert(image != (Image *) NULL);
1520 assert(image->signature == MagickSignature);
1521 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1523 if (q == (Quantum *) NULL)
1524 return((Quantum *) NULL);
1525 cache_info=(CacheInfo *) image->cache;
1526 assert(cache_info->signature == MagickSignature);
1527 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1529 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1530 return((Quantum *) NULL);
1531 if (cache_info->metacontent_extent != 0)
1532 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1533 return((Quantum *) NULL);
1538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1542 + 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 %
1546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1548 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1549 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1551 % The format of the GetAuthenticPixelsFromCache() method is:
1553 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1555 % A description of each parameter follows:
1557 % o image: the image.
1560 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1566 id = GetOpenMPThreadId();
1568 assert(image != (const Image *) NULL);
1569 assert(image->signature == MagickSignature);
1570 assert(image->cache != (Cache) NULL);
1571 cache_info=(CacheInfo *) image->cache;
1572 assert(cache_info->signature == MagickSignature);
1573 assert(id < (int) cache_info->number_threads);
1574 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1582 % G e t A u t h e n t i c P i x e l Q u e u e %
1586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588 % GetAuthenticPixelQueue() returns the authentic pixels associated
1589 % corresponding with the last call to QueueAuthenticPixels() or
1590 % GetAuthenticPixels().
1592 % The format of the GetAuthenticPixelQueue() method is:
1594 % Quantum *GetAuthenticPixelQueue(const Image image)
1596 % A description of each parameter follows:
1598 % o image: the image.
1601 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1607 id = GetOpenMPThreadId();
1609 assert(image != (const Image *) NULL);
1610 assert(image->signature == MagickSignature);
1611 assert(image->cache != (Cache) NULL);
1612 cache_info=(CacheInfo *) image->cache;
1613 assert(cache_info->signature == MagickSignature);
1614 if (cache_info->methods.get_authentic_pixels_from_handler !=
1615 (GetAuthenticPixelsFromHandler) NULL)
1616 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1617 assert(id < (int) cache_info->number_threads);
1618 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1626 % G e t A u t h e n t i c P i x e l s %
1629 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1632 % region is successfully accessed, a pointer to a Quantum array
1633 % representing the region is returned, otherwise NULL is returned.
1635 % The returned pointer may point to a temporary working copy of the pixels
1636 % or it may point to the original pixels in memory. Performance is maximized
1637 % if the selected region is part of one row, or one or more full rows, since
1638 % then there is opportunity to access the pixels in-place (without a copy)
1639 % if the image is in memory, or in a memory-mapped file. The returned pointer
1640 % must *never* be deallocated by the user.
1642 % Pixels accessed via the returned pointer represent a simple array of type
1643 % Quantum. If the image has corresponding metacontent,call
1644 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1645 % meta-content corresponding to the region. Once the Quantum array has
1646 % been updated, the changes must be saved back to the underlying image using
1647 % SyncAuthenticPixels() or they may be lost.
1649 % The format of the GetAuthenticPixels() method is:
1651 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1652 % const ssize_t y,const size_t columns,const size_t rows,
1653 % ExceptionInfo *exception)
1655 % A description of each parameter follows:
1657 % o image: the image.
1659 % o x,y,columns,rows: These values define the perimeter of a region of
1662 % o exception: return any errors or warnings in this structure.
1665 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1666 const ssize_t y,const size_t columns,const size_t rows,
1667 ExceptionInfo *exception)
1673 id = GetOpenMPThreadId();
1678 assert(image != (Image *) NULL);
1679 assert(image->signature == MagickSignature);
1680 assert(image->cache != (Cache) NULL);
1681 cache_info=(CacheInfo *) image->cache;
1682 assert(cache_info->signature == MagickSignature);
1683 if (cache_info->methods.get_authentic_pixels_handler !=
1684 (GetAuthenticPixelsHandler) NULL)
1686 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1690 assert(id < (int) cache_info->number_threads);
1691 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1692 cache_info->nexus_info[id],exception);
1697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1701 + G e t A u t h e n t i c P i x e l s C a c h e %
1705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1707 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1708 % as defined by the geometry parameters. A pointer to the pixels is returned
1709 % if the pixels are transferred, otherwise a NULL is returned.
1711 % The format of the GetAuthenticPixelsCache() method is:
1713 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1714 % const ssize_t y,const size_t columns,const size_t rows,
1715 % ExceptionInfo *exception)
1717 % A description of each parameter follows:
1719 % o image: the image.
1721 % o x,y,columns,rows: These values define the perimeter of a region of
1724 % o exception: return any errors or warnings in this structure.
1727 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1728 const ssize_t y,const size_t columns,const size_t rows,
1729 ExceptionInfo *exception)
1735 id = GetOpenMPThreadId();
1740 assert(image != (const Image *) NULL);
1741 assert(image->signature == MagickSignature);
1742 assert(image->cache != (Cache) NULL);
1743 cache_info=(CacheInfo *) image->cache;
1744 if (cache_info == (Cache) NULL)
1745 return((Quantum *) NULL);
1746 assert(cache_info->signature == MagickSignature);
1747 assert(id < (int) cache_info->number_threads);
1748 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1749 cache_info->nexus_info[id],exception);
1754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1758 + G e t I m a g e E x t e n t %
1762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1764 % GetImageExtent() returns the extent of the pixels associated corresponding
1765 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1767 % The format of the GetImageExtent() method is:
1769 % MagickSizeType GetImageExtent(const Image *image)
1771 % A description of each parameter follows:
1773 % o image: the image.
1776 MagickExport MagickSizeType GetImageExtent(const Image *image)
1782 id = GetOpenMPThreadId();
1784 assert(image != (Image *) NULL);
1785 assert(image->signature == MagickSignature);
1786 if (image->debug != MagickFalse)
1787 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1788 assert(image->cache != (Cache) NULL);
1789 cache_info=(CacheInfo *) image->cache;
1790 assert(cache_info->signature == MagickSignature);
1791 assert(id < (int) cache_info->number_threads);
1792 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1800 + G e t I m a g e P i x e l C a c h e %
1804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1806 % GetImagePixelCache() ensures that there is only a single reference to the
1807 % pixel cache to be modified, updating the provided cache pointer to point to
1808 % a clone of the original pixel cache if necessary.
1810 % The format of the GetImagePixelCache method is:
1812 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1813 % ExceptionInfo *exception)
1815 % A description of each parameter follows:
1817 % o image: the image.
1819 % o clone: any value other than MagickFalse clones the cache pixels.
1821 % o exception: return any errors or warnings in this structure.
1825 static inline MagickBooleanType ValidatePixelCacheMorphology(
1826 const Image *restrict image)
1829 *restrict cache_info;
1831 const PixelChannelMap
1836 Does the image match the pixel cache morphology?
1838 cache_info=(CacheInfo *) image->cache;
1839 p=image->channel_map;
1840 q=cache_info->channel_map;
1841 if ((image->storage_class != cache_info->storage_class) ||
1842 (image->colorspace != cache_info->colorspace) ||
1843 (image->alpha_trait != cache_info->alpha_trait) ||
1844 (image->mask != cache_info->mask) ||
1845 (image->columns != cache_info->columns) ||
1846 (image->rows != cache_info->rows) ||
1847 (image->number_channels != cache_info->number_channels) ||
1848 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1849 (image->metacontent_extent != cache_info->metacontent_extent) ||
1850 (cache_info->nexus_info == (NexusInfo **) NULL))
1851 return(MagickFalse);
1855 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1856 ExceptionInfo *exception)
1865 static MagickSizeType
1871 cache_timestamp = 0;
1874 LockSemaphoreInfo(image->semaphore);
1875 if (cpu_throttle == 0)
1881 Set CPU throttle in milleseconds.
1883 cpu_throttle=MagickResourceInfinity;
1884 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1885 if (limit == (char *) NULL)
1886 limit=GetPolicyValue("throttle");
1887 if (limit != (char *) NULL)
1889 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1890 limit=DestroyString(limit);
1893 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1894 MagickDelay(cpu_throttle);
1895 if (time_limit == 0)
1898 Set the expire time in seconds.
1900 time_limit=GetMagickResourceLimit(TimeResource);
1901 cache_timestamp=time((time_t *) NULL);
1903 if ((time_limit != MagickResourceInfinity) &&
1904 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1905 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1906 assert(image->cache != (Cache) NULL);
1907 cache_info=(CacheInfo *) image->cache;
1908 destroy=MagickFalse;
1909 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1911 LockSemaphoreInfo(cache_info->semaphore);
1912 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1923 clone_image=(*image);
1924 clone_image.semaphore=AllocateSemaphoreInfo();
1925 clone_image.reference_count=1;
1926 clone_image.cache=ClonePixelCache(cache_info);
1927 clone_info=(CacheInfo *) clone_image.cache;
1928 status=OpenPixelCache(&clone_image,IOMode,exception);
1929 if (status != MagickFalse)
1931 if (clone != MagickFalse)
1932 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1933 if (status != MagickFalse)
1935 if (cache_info->reference_count == 1)
1936 cache_info->nexus_info=(NexusInfo **) NULL;
1938 image->cache=clone_image.cache;
1941 DestroySemaphoreInfo(&clone_image.semaphore);
1943 UnlockSemaphoreInfo(cache_info->semaphore);
1945 if (destroy != MagickFalse)
1946 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1947 if (status != MagickFalse)
1950 Ensure the image matches the pixel cache morphology.
1952 image->taint=MagickTrue;
1953 image->type=UndefinedType;
1954 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1956 status=OpenPixelCache(image,IOMode,exception);
1957 cache_info=(CacheInfo *) image->cache;
1958 if (cache_info->type == DiskCache)
1959 (void) ClosePixelCacheOnDisk(cache_info);
1962 UnlockSemaphoreInfo(image->semaphore);
1963 if (status == MagickFalse)
1964 return((Cache) NULL);
1965 return(image->cache);
1969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1973 + G e t I m a g e P i x e l C a c h e T y p e %
1977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1979 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1980 % DiskCache, MemoryCache, MapCache, or PingCache.
1982 % The format of the GetImagePixelCacheType() method is:
1984 % CacheType GetImagePixelCacheType(const Image *image)
1986 % A description of each parameter follows:
1988 % o image: the image.
1991 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1996 assert(image != (Image *) NULL);
1997 assert(image->signature == MagickSignature);
1998 assert(image->cache != (Cache) NULL);
1999 cache_info=(CacheInfo *) image->cache;
2000 assert(cache_info->signature == MagickSignature);
2001 return(cache_info->type);
2005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2009 % G e t O n e A u t h e n t i c P i x e l %
2013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2015 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2016 % location. The image background color is returned if an error occurs.
2018 % The format of the GetOneAuthenticPixel() method is:
2020 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2021 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2023 % A description of each parameter follows:
2025 % o image: the image.
2027 % o x,y: These values define the location of the pixel to return.
2029 % o pixel: return a pixel at the specified (x,y) location.
2031 % o exception: return any errors or warnings in this structure.
2034 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2035 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2046 assert(image != (Image *) NULL);
2047 assert(image->signature == MagickSignature);
2048 assert(image->cache != (Cache) NULL);
2049 cache_info=(CacheInfo *) image->cache;
2050 assert(cache_info->signature == MagickSignature);
2051 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2052 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2053 (GetOneAuthenticPixelFromHandler) NULL)
2054 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2056 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2057 if (q == (Quantum *) NULL)
2059 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2060 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2061 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2062 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2063 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2064 return(MagickFalse);
2066 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2071 channel=GetPixelChannelChannel(image,i);
2072 pixel[channel]=q[i];
2078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2082 + 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 %
2086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2088 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2089 % location. The image background color is returned if an error occurs.
2091 % The format of the GetOneAuthenticPixelFromCache() method is:
2093 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2094 % const ssize_t x,const ssize_t y,Quantum *pixel,
2095 % ExceptionInfo *exception)
2097 % A description of each parameter follows:
2099 % o image: the image.
2101 % o x,y: These values define the location of the pixel to return.
2103 % o pixel: return a pixel at the specified (x,y) location.
2105 % o exception: return any errors or warnings in this structure.
2108 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2109 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2115 id = GetOpenMPThreadId();
2123 assert(image != (const Image *) NULL);
2124 assert(image->signature == MagickSignature);
2125 assert(image->cache != (Cache) NULL);
2126 cache_info=(CacheInfo *) image->cache;
2127 assert(cache_info->signature == MagickSignature);
2128 assert(id < (int) cache_info->number_threads);
2129 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2130 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2132 if (q == (Quantum *) NULL)
2134 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2135 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2136 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2137 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2138 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2139 return(MagickFalse);
2141 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2146 channel=GetPixelChannelChannel(image,i);
2147 pixel[channel]=q[i];
2153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2157 % G e t O n e V i r t u a l P i x e l %
2161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2163 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2164 % (x,y) location. The image background color is returned if an error occurs.
2165 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2167 % The format of the GetOneVirtualPixel() method is:
2169 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2170 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2172 % A description of each parameter follows:
2174 % o image: the image.
2176 % o x,y: These values define the location of the pixel to return.
2178 % o pixel: return a pixel at the specified (x,y) location.
2180 % o exception: return any errors or warnings in this structure.
2183 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2184 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2190 id = GetOpenMPThreadId();
2198 assert(image != (const Image *) NULL);
2199 assert(image->signature == MagickSignature);
2200 assert(image->cache != (Cache) NULL);
2201 cache_info=(CacheInfo *) image->cache;
2202 assert(cache_info->signature == MagickSignature);
2203 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2204 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2205 (GetOneVirtualPixelFromHandler) NULL)
2206 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2207 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2208 assert(id < (int) cache_info->number_threads);
2209 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2210 1UL,1UL,cache_info->nexus_info[id],exception);
2211 if (p == (const Quantum *) NULL)
2213 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2214 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2215 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2216 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2217 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2218 return(MagickFalse);
2220 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2225 channel=GetPixelChannelChannel(image,i);
2226 pixel[channel]=p[i];
2232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2236 + 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 %
2240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2243 % specified (x,y) location. The image background color is returned if an
2246 % The format of the GetOneVirtualPixelFromCache() method is:
2248 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2249 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2250 % Quantum *pixel,ExceptionInfo *exception)
2252 % A description of each parameter follows:
2254 % o image: the image.
2256 % o virtual_pixel_method: the virtual pixel method.
2258 % o x,y: These values define the location of the pixel to return.
2260 % o pixel: return a pixel at the specified (x,y) location.
2262 % o exception: return any errors or warnings in this structure.
2265 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2266 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2267 Quantum *pixel,ExceptionInfo *exception)
2273 id = GetOpenMPThreadId();
2281 assert(image != (const Image *) NULL);
2282 assert(image->signature == MagickSignature);
2283 assert(image->cache != (Cache) NULL);
2284 cache_info=(CacheInfo *) image->cache;
2285 assert(cache_info->signature == MagickSignature);
2286 assert(id < (int) cache_info->number_threads);
2287 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2288 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2289 cache_info->nexus_info[id],exception);
2290 if (p == (const Quantum *) NULL)
2292 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2293 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2294 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2295 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2296 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2297 return(MagickFalse);
2299 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2304 channel=GetPixelChannelChannel(image,i);
2305 pixel[channel]=p[i];
2311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315 % G e t O n e V i r t u a l P i x e l I n f o %
2319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2321 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2322 % location. The image background color is returned if an error occurs. If
2323 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2325 % The format of the GetOneVirtualPixelInfo() method is:
2327 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2328 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2329 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2331 % A description of each parameter follows:
2333 % o image: the image.
2335 % o virtual_pixel_method: the virtual pixel method.
2337 % o x,y: these values define the location of the pixel to return.
2339 % o pixel: return a pixel at the specified (x,y) location.
2341 % o exception: return any errors or warnings in this structure.
2344 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2345 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2346 PixelInfo *pixel,ExceptionInfo *exception)
2352 id = GetOpenMPThreadId();
2354 register const Quantum
2357 assert(image != (const Image *) NULL);
2358 assert(image->signature == MagickSignature);
2359 assert(image->cache != (Cache) NULL);
2360 cache_info=(CacheInfo *) image->cache;
2361 assert(cache_info->signature == MagickSignature);
2362 assert(id < (int) cache_info->number_threads);
2363 GetPixelInfo(image,pixel);
2364 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2365 cache_info->nexus_info[id],exception);
2366 if (p == (const Quantum *) NULL)
2367 return(MagickFalse);
2368 GetPixelInfoPixel(image,p,pixel);
2373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2377 + G e t P i x e l C a c h e C o l o r s p a c e %
2381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2383 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2385 % The format of the GetPixelCacheColorspace() method is:
2387 % Colorspace GetPixelCacheColorspace(Cache cache)
2389 % A description of each parameter follows:
2391 % o cache: the pixel cache.
2394 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2399 assert(cache != (Cache) NULL);
2400 cache_info=(CacheInfo *) cache;
2401 assert(cache_info->signature == MagickSignature);
2402 if (cache_info->debug != MagickFalse)
2403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2404 cache_info->filename);
2405 return(cache_info->colorspace);
2409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2413 + G e t P i x e l C a c h e M e t h o d s %
2417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2419 % GetPixelCacheMethods() initializes the CacheMethods structure.
2421 % The format of the GetPixelCacheMethods() method is:
2423 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2425 % A description of each parameter follows:
2427 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2430 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2432 assert(cache_methods != (CacheMethods *) NULL);
2433 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2434 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2435 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2436 cache_methods->get_virtual_metacontent_from_handler=
2437 GetVirtualMetacontentFromCache;
2438 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2439 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2440 cache_methods->get_authentic_metacontent_from_handler=
2441 GetAuthenticMetacontentFromCache;
2442 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2443 cache_methods->get_one_authentic_pixel_from_handler=
2444 GetOneAuthenticPixelFromCache;
2445 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2446 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2447 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2455 + G e t P i x e l C a c h e N e x u s E x t e n t %
2459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2461 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2462 % corresponding with the last call to SetPixelCacheNexusPixels() or
2463 % GetPixelCacheNexusPixels().
2465 % The format of the GetPixelCacheNexusExtent() method is:
2467 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2468 % NexusInfo *nexus_info)
2470 % A description of each parameter follows:
2472 % o nexus_info: the nexus info.
2475 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2476 NexusInfo *nexus_info)
2484 assert(cache != NULL);
2485 cache_info=(CacheInfo *) cache;
2486 assert(cache_info->signature == MagickSignature);
2487 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2489 return((MagickSizeType) cache_info->columns*cache_info->rows);
2494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2498 + 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 %
2502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2504 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2507 % The format of the GetPixelCacheNexusMetacontent() method is:
2509 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2510 % NexusInfo *nexus_info)
2512 % A description of each parameter follows:
2514 % o cache: the pixel cache.
2516 % o nexus_info: the cache nexus to return the meta-content.
2519 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2520 NexusInfo *nexus_info)
2525 assert(cache != NULL);
2526 cache_info=(CacheInfo *) cache;
2527 assert(cache_info->signature == MagickSignature);
2528 if (cache_info->storage_class == UndefinedClass)
2529 return((void *) NULL);
2530 return(nexus_info->metacontent);
2534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2538 + G e t P i x e l C a c h e N e x u s P i x e l s %
2542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2544 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2547 % The format of the GetPixelCacheNexusPixels() method is:
2549 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2550 % NexusInfo *nexus_info)
2552 % A description of each parameter follows:
2554 % o cache: the pixel cache.
2556 % o nexus_info: the cache nexus to return the pixels.
2559 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2560 NexusInfo *nexus_info)
2565 assert(cache != NULL);
2566 cache_info=(CacheInfo *) cache;
2567 assert(cache_info->signature == MagickSignature);
2568 if (cache_info->storage_class == UndefinedClass)
2569 return((Quantum *) NULL);
2570 return(nexus_info->pixels);
2574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2578 + G e t P i x e l C a c h e P i x e l s %
2582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2584 % GetPixelCachePixels() returns the pixels associated with the specified image.
2586 % The format of the GetPixelCachePixels() method is:
2588 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2589 % ExceptionInfo *exception)
2591 % A description of each parameter follows:
2593 % o image: the image.
2595 % o length: the pixel cache length.
2597 % o exception: return any errors or warnings in this structure.
2600 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2601 ExceptionInfo *exception)
2606 assert(image != (const Image *) NULL);
2607 assert(image->signature == MagickSignature);
2608 assert(image->cache != (Cache) NULL);
2609 assert(length != (MagickSizeType *) NULL);
2610 assert(exception != (ExceptionInfo *) NULL);
2611 assert(exception->signature == MagickSignature);
2612 cache_info=(CacheInfo *) image->cache;
2613 assert(cache_info->signature == MagickSignature);
2615 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2616 return((void *) NULL);
2617 *length=cache_info->length;
2618 return((void *) cache_info->pixels);
2622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2626 + 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 %
2630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2632 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2634 % The format of the GetPixelCacheStorageClass() method is:
2636 % ClassType GetPixelCacheStorageClass(Cache cache)
2638 % A description of each parameter follows:
2640 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2642 % o cache: the pixel cache.
2645 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2650 assert(cache != (Cache) NULL);
2651 cache_info=(CacheInfo *) cache;
2652 assert(cache_info->signature == MagickSignature);
2653 if (cache_info->debug != MagickFalse)
2654 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2655 cache_info->filename);
2656 return(cache_info->storage_class);
2660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2664 + G e t P i x e l C a c h e T i l e S i z e %
2668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2670 % GetPixelCacheTileSize() returns the pixel cache tile size.
2672 % The format of the GetPixelCacheTileSize() method is:
2674 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2677 % A description of each parameter follows:
2679 % o image: the image.
2681 % o width: the optimize cache tile width in pixels.
2683 % o height: the optimize cache tile height in pixels.
2686 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2692 assert(image != (Image *) NULL);
2693 assert(image->signature == MagickSignature);
2694 if (image->debug != MagickFalse)
2695 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2696 cache_info=(CacheInfo *) image->cache;
2697 assert(cache_info->signature == MagickSignature);
2698 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2699 if (GetImagePixelCacheType(image) == DiskCache)
2700 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2709 + 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 %
2713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2715 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2716 % pixel cache. A virtual pixel is any pixel access that is outside the
2717 % boundaries of the image cache.
2719 % The format of the GetPixelCacheVirtualMethod() method is:
2721 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2723 % A description of each parameter follows:
2725 % o image: the image.
2728 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2733 assert(image != (Image *) NULL);
2734 assert(image->signature == MagickSignature);
2735 assert(image->cache != (Cache) NULL);
2736 cache_info=(CacheInfo *) image->cache;
2737 assert(cache_info->signature == MagickSignature);
2738 return(cache_info->virtual_pixel_method);
2742 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2746 + 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 %
2750 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2752 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2753 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2755 % The format of the GetVirtualMetacontentFromCache() method is:
2757 % void *GetVirtualMetacontentFromCache(const Image *image)
2759 % A description of each parameter follows:
2761 % o image: the image.
2764 static const void *GetVirtualMetacontentFromCache(const Image *image)
2770 id = GetOpenMPThreadId();
2775 assert(image != (const Image *) NULL);
2776 assert(image->signature == MagickSignature);
2777 assert(image->cache != (Cache) NULL);
2778 cache_info=(CacheInfo *) image->cache;
2779 assert(cache_info->signature == MagickSignature);
2780 assert(id < (int) cache_info->number_threads);
2781 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2782 cache_info->nexus_info[id]);
2783 return(metacontent);
2787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2791 + 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 %
2795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2797 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2800 % The format of the GetVirtualMetacontentFromNexus() method is:
2802 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2803 % NexusInfo *nexus_info)
2805 % A description of each parameter follows:
2807 % o cache: the pixel cache.
2809 % o nexus_info: the cache nexus to return the meta-content.
2812 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2813 NexusInfo *nexus_info)
2818 assert(cache != (Cache) NULL);
2819 cache_info=(CacheInfo *) cache;
2820 assert(cache_info->signature == MagickSignature);
2821 if (cache_info->storage_class == UndefinedClass)
2822 return((void *) NULL);
2823 return(nexus_info->metacontent);
2827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2831 % G e t V i r t u a l M e t a c o n t e n t %
2835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2837 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2838 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2839 % returned if the meta-content are not available.
2841 % The format of the GetVirtualMetacontent() method is:
2843 % const void *GetVirtualMetacontent(const Image *image)
2845 % A description of each parameter follows:
2847 % o image: the image.
2850 MagickExport const void *GetVirtualMetacontent(const Image *image)
2856 id = GetOpenMPThreadId();
2861 assert(image != (const Image *) NULL);
2862 assert(image->signature == MagickSignature);
2863 assert(image->cache != (Cache) NULL);
2864 cache_info=(CacheInfo *) image->cache;
2865 assert(cache_info->signature == MagickSignature);
2866 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2867 if (metacontent != (void *) NULL)
2868 return(metacontent);
2869 assert(id < (int) cache_info->number_threads);
2870 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2871 cache_info->nexus_info[id]);
2872 return(metacontent);
2876 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2880 + 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 %
2884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2886 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2887 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2888 % is returned if the pixels are transferred, otherwise a NULL is returned.
2890 % The format of the GetVirtualPixelsFromNexus() method is:
2892 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2893 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2894 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2895 % ExceptionInfo *exception)
2897 % A description of each parameter follows:
2899 % o image: the image.
2901 % o virtual_pixel_method: the virtual pixel method.
2903 % o x,y,columns,rows: These values define the perimeter of a region of
2906 % o nexus_info: the cache nexus to acquire.
2908 % o exception: return any errors or warnings in this structure.
2915 0, 48, 12, 60, 3, 51, 15, 63,
2916 32, 16, 44, 28, 35, 19, 47, 31,
2917 8, 56, 4, 52, 11, 59, 7, 55,
2918 40, 24, 36, 20, 43, 27, 39, 23,
2919 2, 50, 14, 62, 1, 49, 13, 61,
2920 34, 18, 46, 30, 33, 17, 45, 29,
2921 10, 58, 6, 54, 9, 57, 5, 53,
2922 42, 26, 38, 22, 41, 25, 37, 21
2925 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2930 index=x+DitherMatrix[x & 0x07]-32L;
2933 if (index >= (ssize_t) columns)
2934 return((ssize_t) columns-1L);
2938 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2943 index=y+DitherMatrix[y & 0x07]-32L;
2946 if (index >= (ssize_t) rows)
2947 return((ssize_t) rows-1L);
2951 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2955 if (x >= (ssize_t) columns)
2956 return((ssize_t) (columns-1));
2960 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2964 if (y >= (ssize_t) rows)
2965 return((ssize_t) (rows-1));
2969 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2971 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2974 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2976 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2979 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2980 const size_t extent)
2986 Compute the remainder of dividing offset by extent. It returns not only
2987 the quotient (tile the offset falls in) but also the positive remainer
2988 within that tile such that 0 <= remainder < extent. This method is
2989 essentially a ldiv() using a floored modulo division rather than the
2990 normal default truncated modulo division.
2992 modulo.quotient=offset/(ssize_t) extent;
2995 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2999 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3000 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3001 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3002 ExceptionInfo *exception)
3019 virtual_pixel[CompositePixelChannel];
3024 register const Quantum
3037 register unsigned char
3044 *virtual_metacontent;
3049 assert(image != (const Image *) NULL);
3050 assert(image->signature == MagickSignature);
3051 assert(image->cache != (Cache) NULL);
3052 cache_info=(CacheInfo *) image->cache;
3053 assert(cache_info->signature == MagickSignature);
3054 if (cache_info->type == UndefinedCache)
3055 return((const Quantum *) NULL);
3058 region.width=columns;
3060 pixels=SetPixelCacheNexusPixels(image,ReadMode,®ion,nexus_info,exception);
3061 if (pixels == (Quantum *) NULL)
3062 return((const Quantum *) NULL);
3064 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3065 nexus_info->region.x;
3066 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3067 nexus_info->region.width-1L;
3068 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3069 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3070 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3071 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3077 Pixel request is inside cache extents.
3079 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3081 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3082 if (status == MagickFalse)
3083 return((const Quantum *) NULL);
3084 if (cache_info->metacontent_extent != 0)
3086 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3087 if (status == MagickFalse)
3088 return((const Quantum *) NULL);
3093 Pixel request is outside cache extents.
3095 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3096 virtual_nexus=AcquirePixelCacheNexus(1);
3097 if (virtual_nexus == (NexusInfo **) NULL)
3099 if (virtual_nexus != (NexusInfo **) NULL)
3100 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3101 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3102 "UnableToGetCacheNexus","`%s'",image->filename);
3103 return((const Quantum *) NULL);
3105 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3106 sizeof(*virtual_pixel));
3107 virtual_metacontent=(void *) NULL;
3108 switch (virtual_pixel_method)
3110 case BackgroundVirtualPixelMethod:
3111 case BlackVirtualPixelMethod:
3112 case GrayVirtualPixelMethod:
3113 case TransparentVirtualPixelMethod:
3114 case MaskVirtualPixelMethod:
3115 case WhiteVirtualPixelMethod:
3116 case EdgeVirtualPixelMethod:
3117 case CheckerTileVirtualPixelMethod:
3118 case HorizontalTileVirtualPixelMethod:
3119 case VerticalTileVirtualPixelMethod:
3121 if (cache_info->metacontent_extent != 0)
3124 Acquire a metacontent buffer.
3126 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3127 cache_info->metacontent_extent);
3128 if (virtual_metacontent == (void *) NULL)
3130 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3131 (void) ThrowMagickException(exception,GetMagickModule(),
3132 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3133 return((const Quantum *) NULL);
3135 (void) ResetMagickMemory(virtual_metacontent,0,
3136 cache_info->metacontent_extent);
3138 switch (virtual_pixel_method)
3140 case BlackVirtualPixelMethod:
3142 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3143 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3144 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3147 case GrayVirtualPixelMethod:
3149 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3150 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3152 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3155 case TransparentVirtualPixelMethod:
3157 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3158 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3159 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3162 case MaskVirtualPixelMethod:
3163 case WhiteVirtualPixelMethod:
3165 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3166 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3167 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3172 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3174 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3176 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3178 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3180 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3190 for (v=0; v < (ssize_t) rows; v++)
3192 for (u=0; u < (ssize_t) columns; u+=length)
3194 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3195 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3196 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3204 Transfer a single pixel.
3206 length=(MagickSizeType) 1;
3207 switch (virtual_pixel_method)
3211 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3212 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3213 1UL,1UL,*virtual_nexus,exception);
3214 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3217 case RandomVirtualPixelMethod:
3219 if (cache_info->random_info == (RandomInfo *) NULL)
3220 cache_info->random_info=AcquireRandomInfo();
3221 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3222 RandomX(cache_info->random_info,cache_info->columns),
3223 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3224 *virtual_nexus,exception);
3225 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3228 case DitherVirtualPixelMethod:
3230 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3231 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3232 1UL,1UL,*virtual_nexus,exception);
3233 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3236 case TileVirtualPixelMethod:
3238 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3239 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3240 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3241 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3243 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3246 case MirrorVirtualPixelMethod:
3248 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3249 if ((x_modulo.quotient & 0x01) == 1L)
3250 x_modulo.remainder=(ssize_t) cache_info->columns-
3251 x_modulo.remainder-1L;
3252 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3253 if ((y_modulo.quotient & 0x01) == 1L)
3254 y_modulo.remainder=(ssize_t) cache_info->rows-
3255 y_modulo.remainder-1L;
3256 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3257 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3259 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3262 case HorizontalTileEdgeVirtualPixelMethod:
3264 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3265 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3266 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3267 *virtual_nexus,exception);
3268 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3271 case VerticalTileEdgeVirtualPixelMethod:
3273 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3274 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3275 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3276 *virtual_nexus,exception);
3277 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3280 case BackgroundVirtualPixelMethod:
3281 case BlackVirtualPixelMethod:
3282 case GrayVirtualPixelMethod:
3283 case TransparentVirtualPixelMethod:
3284 case MaskVirtualPixelMethod:
3285 case WhiteVirtualPixelMethod:
3288 r=virtual_metacontent;
3291 case EdgeVirtualPixelMethod:
3292 case CheckerTileVirtualPixelMethod:
3294 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3295 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3296 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3299 r=virtual_metacontent;
3302 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3303 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3305 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3308 case HorizontalTileVirtualPixelMethod:
3310 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3313 r=virtual_metacontent;
3316 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3317 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3318 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3319 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3321 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3324 case VerticalTileVirtualPixelMethod:
3326 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3329 r=virtual_metacontent;
3332 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3333 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3334 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3335 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3337 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3341 if (p == (const Quantum *) NULL)
3343 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3345 q+=cache_info->number_channels;
3346 if ((s != (void *) NULL) && (r != (const void *) NULL))
3348 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3349 s+=cache_info->metacontent_extent;
3354 Transfer a run of pixels.
3356 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3357 length,1UL,*virtual_nexus,exception);
3358 if (p == (const Quantum *) NULL)
3360 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3361 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3362 q+=length*cache_info->number_channels;
3363 if ((r != (void *) NULL) && (s != (const void *) NULL))
3365 (void) memcpy(s,r,(size_t) length);
3366 s+=length*cache_info->metacontent_extent;
3373 if (virtual_metacontent != (void *) NULL)
3374 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3375 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3384 + G e t V i r t u a l P i x e l C a c h e %
3388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3390 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3391 % cache as defined by the geometry parameters. A pointer to the pixels
3392 % is returned if the pixels are transferred, otherwise a NULL is returned.
3394 % The format of the GetVirtualPixelCache() method is:
3396 % const Quantum *GetVirtualPixelCache(const Image *image,
3397 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3398 % const ssize_t y,const size_t columns,const size_t rows,
3399 % ExceptionInfo *exception)
3401 % A description of each parameter follows:
3403 % o image: the image.
3405 % o virtual_pixel_method: the virtual pixel method.
3407 % o x,y,columns,rows: These values define the perimeter of a region of
3410 % o exception: return any errors or warnings in this structure.
3413 static const Quantum *GetVirtualPixelCache(const Image *image,
3414 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3415 const size_t columns,const size_t rows,ExceptionInfo *exception)
3421 id = GetOpenMPThreadId();
3426 assert(image != (const Image *) NULL);
3427 assert(image->signature == MagickSignature);
3428 assert(image->cache != (Cache) NULL);
3429 cache_info=(CacheInfo *) image->cache;
3430 assert(cache_info->signature == MagickSignature);
3431 assert(id < (int) cache_info->number_threads);
3432 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3433 cache_info->nexus_info[id],exception);
3438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3442 % G e t V i r t u a l P i x e l Q u e u e %
3446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3448 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3449 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3451 % The format of the GetVirtualPixelQueue() method is:
3453 % const Quantum *GetVirtualPixelQueue(const Image image)
3455 % A description of each parameter follows:
3457 % o image: the image.
3460 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3466 id = GetOpenMPThreadId();
3468 assert(image != (const Image *) NULL);
3469 assert(image->signature == MagickSignature);
3470 assert(image->cache != (Cache) NULL);
3471 cache_info=(CacheInfo *) image->cache;
3472 assert(cache_info->signature == MagickSignature);
3473 if (cache_info->methods.get_virtual_pixels_handler !=
3474 (GetVirtualPixelsHandler) NULL)
3475 return(cache_info->methods.get_virtual_pixels_handler(image));
3476 assert(id < (int) cache_info->number_threads);
3477 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3485 % G e t V i r t u a l P i x e l s %
3489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3491 % GetVirtualPixels() returns an immutable pixel region. If the
3492 % region is successfully accessed, a pointer to it is returned, otherwise
3493 % NULL is returned. The returned pointer may point to a temporary working
3494 % copy of the pixels or it may point to the original pixels in memory.
3495 % Performance is maximized if the selected region is part of one row, or one
3496 % or more full rows, since there is opportunity to access the pixels in-place
3497 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3498 % returned pointer must *never* be deallocated by the user.
3500 % Pixels accessed via the returned pointer represent a simple array of type
3501 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3502 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3503 % access the meta-content (of type void) corresponding to the the
3506 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3508 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3509 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3510 % GetCacheViewAuthenticPixels() instead.
3512 % The format of the GetVirtualPixels() method is:
3514 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3515 % const ssize_t y,const size_t columns,const size_t rows,
3516 % ExceptionInfo *exception)
3518 % A description of each parameter follows:
3520 % o image: the image.
3522 % o x,y,columns,rows: These values define the perimeter of a region of
3525 % o exception: return any errors or warnings in this structure.
3528 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3529 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3530 ExceptionInfo *exception)
3536 id = GetOpenMPThreadId();
3541 assert(image != (const Image *) NULL);
3542 assert(image->signature == MagickSignature);
3543 assert(image->cache != (Cache) NULL);
3544 cache_info=(CacheInfo *) image->cache;
3545 assert(cache_info->signature == MagickSignature);
3546 if (cache_info->methods.get_virtual_pixel_handler !=
3547 (GetVirtualPixelHandler) NULL)
3548 return(cache_info->methods.get_virtual_pixel_handler(image,
3549 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3550 assert(id < (int) cache_info->number_threads);
3551 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3552 columns,rows,cache_info->nexus_info[id],exception);
3557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3561 + 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 %
3565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3567 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3568 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3570 % The format of the GetVirtualPixelsCache() method is:
3572 % Quantum *GetVirtualPixelsCache(const Image *image)
3574 % A description of each parameter follows:
3576 % o image: the image.
3579 static const Quantum *GetVirtualPixelsCache(const Image *image)
3585 id = GetOpenMPThreadId();
3587 assert(image != (const Image *) NULL);
3588 assert(image->signature == MagickSignature);
3589 assert(image->cache != (Cache) NULL);
3590 cache_info=(CacheInfo *) image->cache;
3591 assert(cache_info->signature == MagickSignature);
3592 assert(id < (int) cache_info->number_threads);
3593 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3601 + G e t V i r t u a l P i x e l s N e x u s %
3605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3607 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3610 % The format of the GetVirtualPixelsNexus() method is:
3612 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3613 % NexusInfo *nexus_info)
3615 % A description of each parameter follows:
3617 % o cache: the pixel cache.
3619 % o nexus_info: the cache nexus to return the colormap pixels.
3622 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3623 NexusInfo *nexus_info)
3628 assert(cache != (Cache) NULL);
3629 cache_info=(CacheInfo *) cache;
3630 assert(cache_info->signature == MagickSignature);
3631 if (cache_info->storage_class == UndefinedClass)
3632 return((Quantum *) NULL);
3633 return((const Quantum *) nexus_info->pixels);
3637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3641 + O p e n P i x e l C a c h e %
3645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3648 % dimensions, allocating space for the image pixels and optionally the
3649 % metacontent, and memory mapping the cache if it is disk based. The cache
3650 % nexus array is initialized as well.
3652 % The format of the OpenPixelCache() method is:
3654 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3655 % ExceptionInfo *exception)
3657 % A description of each parameter follows:
3659 % o image: the image.
3661 % o mode: ReadMode, WriteMode, or IOMode.
3663 % o exception: return any errors or warnings in this structure.
3667 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3669 cache_info->mapped=MagickFalse;
3670 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3671 (size_t) cache_info->length));
3672 if (cache_info->pixels == (Quantum *) NULL)
3674 cache_info->mapped=MagickTrue;
3675 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3676 cache_info->length);
3680 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3690 cache_info=(CacheInfo *) image->cache;
3691 if (image->debug != MagickFalse)
3694 format[MaxTextExtent],
3695 message[MaxTextExtent];
3697 (void) FormatMagickSize(length,MagickFalse,format);
3698 (void) FormatLocaleString(message,MaxTextExtent,
3699 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3700 cache_info->cache_filename,cache_info->file,format);
3701 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3703 if (length != (MagickSizeType) ((MagickOffsetType) length))
3704 return(MagickFalse);
3705 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3707 return(MagickFalse);
3708 if ((MagickSizeType) offset >= length)
3710 extent=(MagickOffsetType) length-1;
3711 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3712 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3713 if (cache_info->synchronize != MagickFalse)
3718 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3720 return(MagickFalse);
3723 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3726 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3727 ExceptionInfo *exception)
3734 format[MaxTextExtent],
3735 message[MaxTextExtent];
3751 assert(image != (const Image *) NULL);
3752 assert(image->signature == MagickSignature);
3753 assert(image->cache != (Cache) NULL);
3754 if (image->debug != MagickFalse)
3755 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3756 if ((image->columns == 0) || (image->rows == 0))
3757 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3758 cache_info=(CacheInfo *) image->cache;
3759 assert(cache_info->signature == MagickSignature);
3760 source_info=(*cache_info);
3761 source_info.file=(-1);
3762 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3763 image->filename,(double) GetImageIndexInList(image));
3764 cache_info->storage_class=image->storage_class;
3765 cache_info->colorspace=image->colorspace;
3766 cache_info->alpha_trait=image->alpha_trait;
3767 cache_info->mask=image->mask;
3768 cache_info->rows=image->rows;
3769 cache_info->columns=image->columns;
3770 InitializePixelChannelMap(image);
3771 cache_info->number_channels=GetPixelChannels(image);
3772 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3773 sizeof(*image->channel_map));
3774 cache_info->metacontent_extent=image->metacontent_extent;
3775 cache_info->mode=mode;
3776 if (image->ping != MagickFalse)
3778 cache_info->type=PingCache;
3779 cache_info->pixels=(Quantum *) NULL;
3780 cache_info->metacontent=(void *) NULL;
3781 cache_info->length=0;
3784 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3785 packet_size=cache_info->number_channels*sizeof(Quantum);
3786 if (image->metacontent_extent != 0)
3787 packet_size+=cache_info->metacontent_extent;
3788 length=number_pixels*packet_size;
3789 columns=(size_t) (length/cache_info->rows/packet_size);
3790 if (cache_info->columns != columns)
3791 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3793 cache_info->length=length;
3794 status=AcquireMagickResource(AreaResource,cache_info->length);
3795 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3796 cache_info->metacontent_extent);
3797 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3799 status=AcquireMagickResource(MemoryResource,cache_info->length);
3800 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3801 (cache_info->type == MemoryCache))
3803 AllocatePixelCachePixels(cache_info);
3804 if (cache_info->pixels == (Quantum *) NULL)
3805 cache_info->pixels=source_info.pixels;
3809 Create memory pixel cache.
3812 cache_info->type=MemoryCache;
3813 cache_info->metacontent=(void *) NULL;
3814 if (cache_info->metacontent_extent != 0)
3815 cache_info->metacontent=(void *) (cache_info->pixels+
3816 number_pixels*cache_info->number_channels);
3817 if ((source_info.storage_class != UndefinedClass) &&
3820 status=ClonePixelCachePixels(cache_info,&source_info,
3822 RelinquishPixelCachePixels(&source_info);
3824 if (image->debug != MagickFalse)
3826 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3827 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3829 (void) FormatLocaleString(message,MaxTextExtent,
3830 "open %s (%s %s, %.20gx%.20gx%.20g %s)",
3831 cache_info->filename,cache_info->mapped != MagickFalse ?
3832 "Anonymous" : "Heap",type,(double) cache_info->columns,
3833 (double) cache_info->rows,(double)
3834 cache_info->number_channels,format);
3835 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3841 RelinquishMagickResource(MemoryResource,cache_info->length);
3844 Create pixel cache on disk.
3846 status=AcquireMagickResource(DiskResource,cache_info->length);
3847 if ((status == MagickFalse) || (cache_info->type == DistributedCache))
3852 if (cache_info->type == DistributedCache)
3853 RelinquishMagickResource(DiskResource,cache_info->length);
3854 server_info=AcquireDistributeCacheInfo(exception);
3855 if (server_info != (DistributeCacheInfo *) NULL)
3857 status=OpenDistributePixelCache(server_info,image);
3858 if (status == MagickFalse)
3859 server_info=DestroyDistributeCacheInfo(server_info);
3863 Create a distributed pixel cache.
3865 cache_info->server_info=server_info;
3866 cache_info->type=DistributedCache;
3867 (void) FormatLocaleString(cache_info->cache_filename,
3868 MaxTextExtent,"%s:%d",
3869 GetDistributeCacheHostname(cache_info->server_info),
3870 GetDistributeCachePort(cache_info->server_info));
3871 if ((source_info.storage_class != UndefinedClass) &&
3874 status=ClonePixelCachePixels(cache_info,&source_info,
3876 RelinquishPixelCachePixels(&source_info);
3878 if (image->debug != MagickFalse)
3880 (void) FormatMagickSize(cache_info->length,MagickFalse,
3882 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3884 (void) FormatLocaleString(message,MaxTextExtent,
3885 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3886 cache_info->filename,cache_info->cache_filename,
3887 GetDistributeCacheFile(cache_info->server_info),type,
3888 (double) cache_info->columns,(double) cache_info->rows,
3889 (double) cache_info->number_channels,format);
3890 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3896 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3897 "CacheResourcesExhausted","`%s'",image->filename);
3898 return(MagickFalse);
3900 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3902 (void) ClosePixelCacheOnDisk(cache_info);
3903 *cache_info->cache_filename='\0';
3905 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3907 RelinquishMagickResource(DiskResource,cache_info->length);
3908 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3910 return(MagickFalse);
3912 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3913 cache_info->length);
3914 if (status == MagickFalse)
3916 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3918 return(MagickFalse);
3920 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3921 cache_info->metacontent_extent);
3922 if (length != (MagickSizeType) ((size_t) length))
3923 cache_info->type=DiskCache;
3926 status=AcquireMagickResource(MapResource,cache_info->length);
3927 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3928 (cache_info->type != MemoryCache))
3929 cache_info->type=DiskCache;
3932 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3933 cache_info->offset,(size_t) cache_info->length);
3934 if (cache_info->pixels == (Quantum *) NULL)
3936 cache_info->type=DiskCache;
3937 cache_info->pixels=source_info.pixels;
3942 Create file-backed memory-mapped pixel cache.
3945 (void) ClosePixelCacheOnDisk(cache_info);
3946 cache_info->type=MapCache;
3947 cache_info->mapped=MagickTrue;
3948 cache_info->metacontent=(void *) NULL;
3949 if (cache_info->metacontent_extent != 0)
3950 cache_info->metacontent=(void *) (cache_info->pixels+
3951 number_pixels*cache_info->number_channels);
3952 if ((source_info.storage_class != UndefinedClass) &&
3955 status=ClonePixelCachePixels(cache_info,&source_info,
3957 RelinquishPixelCachePixels(&source_info);
3959 if (image->debug != MagickFalse)
3961 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3962 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3964 (void) FormatLocaleString(message,MaxTextExtent,
3965 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",
3966 cache_info->filename,cache_info->cache_filename,
3967 cache_info->file,type,(double) cache_info->columns,(double)
3968 cache_info->rows,(double) cache_info->number_channels,
3970 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3976 RelinquishMagickResource(MapResource,cache_info->length);
3979 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3981 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3982 RelinquishPixelCachePixels(&source_info);
3984 if (image->debug != MagickFalse)
3986 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3987 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
3989 (void) FormatLocaleString(message,MaxTextExtent,
3990 "open %s (%s[%d], %s, %.20gx%.20gx%.20g %s)",cache_info->filename,
3991 cache_info->cache_filename,cache_info->file,type,(double)
3992 cache_info->columns,(double) cache_info->rows,(double)
3993 cache_info->number_channels,format);
3994 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4004 + P e r s i s t P i x e l C a c h e %
4008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4010 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4011 % persistent pixel cache is one that resides on disk and is not destroyed
4012 % when the program exits.
4014 % The format of the PersistPixelCache() method is:
4016 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4017 % const MagickBooleanType attach,MagickOffsetType *offset,
4018 % ExceptionInfo *exception)
4020 % A description of each parameter follows:
4022 % o image: the image.
4024 % o filename: the persistent pixel cache filename.
4026 % o attach: A value other than zero initializes the persistent pixel cache.
4028 % o initialize: A value other than zero initializes the persistent pixel
4031 % o offset: the offset in the persistent cache to store pixels.
4033 % o exception: return any errors or warnings in this structure.
4036 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4037 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4038 ExceptionInfo *exception)
4053 assert(image != (Image *) NULL);
4054 assert(image->signature == MagickSignature);
4055 if (image->debug != MagickFalse)
4056 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4057 assert(image->cache != (void *) NULL);
4058 assert(filename != (const char *) NULL);
4059 assert(offset != (MagickOffsetType *) NULL);
4060 page_size=GetMagickPageSize();
4061 cache_info=(CacheInfo *) image->cache;
4062 assert(cache_info->signature == MagickSignature);
4063 if (attach != MagickFalse)
4066 Attach existing persistent pixel cache.
4068 if (image->debug != MagickFalse)
4069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4070 "attach persistent cache");
4071 (void) CopyMagickString(cache_info->cache_filename,filename,
4073 cache_info->type=DiskCache;
4074 cache_info->offset=(*offset);
4075 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4076 return(MagickFalse);
4077 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4080 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4081 (cache_info->reference_count == 1))
4083 LockSemaphoreInfo(cache_info->semaphore);
4084 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4085 (cache_info->reference_count == 1))
4091 Usurp existing persistent pixel cache.
4093 status=rename_utf8(cache_info->cache_filename,filename);
4096 (void) CopyMagickString(cache_info->cache_filename,filename,
4098 *offset+=cache_info->length+page_size-(cache_info->length %
4100 UnlockSemaphoreInfo(cache_info->semaphore);
4101 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4102 if (image->debug != MagickFalse)
4103 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4104 "Usurp resident persistent cache");
4108 UnlockSemaphoreInfo(cache_info->semaphore);
4111 Clone persistent pixel cache.
4113 clone_image=(*image);
4114 clone_info=(CacheInfo *) clone_image.cache;
4115 image->cache=ClonePixelCache(cache_info);
4116 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4117 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4118 cache_info->type=DiskCache;
4119 cache_info->offset=(*offset);
4120 cache_info=(CacheInfo *) image->cache;
4121 status=OpenPixelCache(image,IOMode,exception);
4122 if (status != MagickFalse)
4123 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4124 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4125 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4134 + 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 %
4138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4140 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4141 % defined by the region rectangle and returns a pointer to the region. This
4142 % region is subsequently transferred from the pixel cache with
4143 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4144 % pixels are transferred, otherwise a NULL is returned.
4146 % The format of the QueueAuthenticPixelCacheNexus() method is:
4148 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4149 % const ssize_t y,const size_t columns,const size_t rows,
4150 % const MagickBooleanType clone,NexusInfo *nexus_info,
4151 % ExceptionInfo *exception)
4153 % A description of each parameter follows:
4155 % o image: the image.
4157 % o x,y,columns,rows: These values define the perimeter of a region of
4160 % o nexus_info: the cache nexus to set.
4162 % o clone: clone the pixel cache.
4164 % o exception: return any errors or warnings in this structure.
4167 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4168 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4169 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4184 Validate pixel cache geometry.
4186 assert(image != (const Image *) NULL);
4187 assert(image->signature == MagickSignature);
4188 assert(image->cache != (Cache) NULL);
4189 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4190 if (cache_info == (Cache) NULL)
4191 return((Quantum *) NULL);
4192 assert(cache_info->signature == MagickSignature);
4193 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4195 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4196 "NoPixelsDefinedInCache","`%s'",image->filename);
4197 return((Quantum *) NULL);
4199 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4200 (y >= (ssize_t) cache_info->rows))
4202 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4203 "PixelsAreNotAuthentic","`%s'",image->filename);
4204 return((Quantum *) NULL);
4206 offset=(MagickOffsetType) y*cache_info->columns+x;
4208 return((Quantum *) NULL);
4209 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4210 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4211 if ((MagickSizeType) offset >= number_pixels)
4212 return((Quantum *) NULL);
4218 region.width=columns;
4220 return(SetPixelCacheNexusPixels(image,WriteMode,®ion,nexus_info,exception));
4224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4228 + 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 %
4232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4234 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4235 % defined by the region rectangle and returns a pointer to the region. This
4236 % region is subsequently transferred from the pixel cache with
4237 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4238 % pixels are transferred, otherwise a NULL is returned.
4240 % The format of the QueueAuthenticPixelsCache() method is:
4242 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4243 % const ssize_t y,const size_t columns,const size_t rows,
4244 % ExceptionInfo *exception)
4246 % A description of each parameter follows:
4248 % o image: the image.
4250 % o x,y,columns,rows: These values define the perimeter of a region of
4253 % o exception: return any errors or warnings in this structure.
4256 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4257 const ssize_t y,const size_t columns,const size_t rows,
4258 ExceptionInfo *exception)
4264 id = GetOpenMPThreadId();
4269 assert(image != (const Image *) NULL);
4270 assert(image->signature == MagickSignature);
4271 assert(image->cache != (Cache) NULL);
4272 cache_info=(CacheInfo *) image->cache;
4273 assert(cache_info->signature == MagickSignature);
4274 assert(id < (int) cache_info->number_threads);
4275 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4276 cache_info->nexus_info[id],exception);
4281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4285 % Q u e u e A u t h e n t i c P i x e l s %
4289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4291 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4292 % successfully initialized a pointer to a Quantum array representing the
4293 % region is returned, otherwise NULL is returned. The returned pointer may
4294 % point to a temporary working buffer for the pixels or it may point to the
4295 % final location of the pixels in memory.
4297 % Write-only access means that any existing pixel values corresponding to
4298 % the region are ignored. This is useful if the initial image is being
4299 % created from scratch, or if the existing pixel values are to be
4300 % completely replaced without need to refer to their pre-existing values.
4301 % The application is free to read and write the pixel buffer returned by
4302 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4303 % initialize the pixel array values. Initializing pixel array values is the
4304 % application's responsibility.
4306 % Performance is maximized if the selected region is part of one row, or
4307 % one or more full rows, since then there is opportunity to access the
4308 % pixels in-place (without a copy) if the image is in memory, or in a
4309 % memory-mapped file. The returned pointer must *never* be deallocated
4312 % Pixels accessed via the returned pointer represent a simple array of type
4313 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4314 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4315 % obtain the meta-content (of type void) corresponding to the region.
4316 % Once the Quantum (and/or Quantum) array has been updated, the
4317 % changes must be saved back to the underlying image using
4318 % SyncAuthenticPixels() or they may be lost.
4320 % The format of the QueueAuthenticPixels() method is:
4322 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4323 % const ssize_t y,const size_t columns,const size_t rows,
4324 % ExceptionInfo *exception)
4326 % A description of each parameter follows:
4328 % o image: the image.
4330 % o x,y,columns,rows: These values define the perimeter of a region of
4333 % o exception: return any errors or warnings in this structure.
4336 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4337 const ssize_t y,const size_t columns,const size_t rows,
4338 ExceptionInfo *exception)
4344 id = GetOpenMPThreadId();
4349 assert(image != (Image *) NULL);
4350 assert(image->signature == MagickSignature);
4351 assert(image->cache != (Cache) NULL);
4352 cache_info=(CacheInfo *) image->cache;
4353 assert(cache_info->signature == MagickSignature);
4354 if (cache_info->methods.queue_authentic_pixels_handler !=
4355 (QueueAuthenticPixelsHandler) NULL)
4357 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4361 assert(id < (int) cache_info->number_threads);
4362 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4363 cache_info->nexus_info[id],exception);
4368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4372 + 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 %
4376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4378 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4381 % The format of the ReadPixelCacheMetacontent() method is:
4383 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4384 % NexusInfo *nexus_info,ExceptionInfo *exception)
4386 % A description of each parameter follows:
4388 % o cache_info: the pixel cache.
4390 % o nexus_info: the cache nexus to read the metacontent.
4392 % o exception: return any errors or warnings in this structure.
4395 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4396 NexusInfo *nexus_info,ExceptionInfo *exception)
4409 register unsigned char
4415 if (cache_info->metacontent_extent == 0)
4416 return(MagickFalse);
4417 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4419 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4420 nexus_info->region.x;
4421 length=(MagickSizeType) nexus_info->region.width*
4422 cache_info->metacontent_extent;
4423 rows=nexus_info->region.height;
4425 q=(unsigned char *) nexus_info->metacontent;
4426 switch (cache_info->type)
4431 register unsigned char
4435 Read meta-content from memory.
4437 if ((cache_info->columns == nexus_info->region.width) &&
4438 (extent == (MagickSizeType) ((size_t) extent)))
4443 p=(unsigned char *) cache_info->metacontent+offset*
4444 cache_info->metacontent_extent;
4445 for (y=0; y < (ssize_t) rows; y++)
4447 (void) memcpy(q,p,(size_t) length);
4448 p+=cache_info->metacontent_extent*cache_info->columns;
4449 q+=cache_info->metacontent_extent*nexus_info->region.width;
4456 Read meta content from disk.
4458 LockSemaphoreInfo(cache_info->file_semaphore);
4459 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4461 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4462 cache_info->cache_filename);
4463 UnlockSemaphoreInfo(cache_info->file_semaphore);
4464 return(MagickFalse);
4466 if ((cache_info->columns == nexus_info->region.width) &&
4467 (extent <= MagickMaxBufferExtent))
4472 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4473 for (y=0; y < (ssize_t) rows; y++)
4475 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4476 cache_info->number_channels*sizeof(Quantum)+offset*
4477 cache_info->metacontent_extent,length,(unsigned char *) q);
4478 if ((MagickSizeType) count != length)
4480 offset+=cache_info->columns;
4481 q+=cache_info->metacontent_extent*nexus_info->region.width;
4483 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4484 (void) ClosePixelCacheOnDisk(cache_info);
4485 UnlockSemaphoreInfo(cache_info->file_semaphore);
4486 if (y < (ssize_t) rows)
4488 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4489 cache_info->cache_filename);
4490 return(MagickFalse);
4494 case DistributedCache:
4503 Read metacontent from distributed cache.
4505 LockSemaphoreInfo(cache_info->file_semaphore);
4506 region=nexus_info->region;
4509 for (y=0; y < (ssize_t) rows; y++)
4511 status=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4512 length,(unsigned char *) q);
4513 if (status == MagickFalse)
4515 q+=cache_info->metacontent_extent*nexus_info->region.width;
4518 UnlockSemaphoreInfo(cache_info->file_semaphore);
4519 if (status == MagickFalse)
4521 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4522 cache_info->cache_filename);
4523 return(MagickFalse);
4530 if ((cache_info->debug != MagickFalse) &&
4531 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4532 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4533 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4534 nexus_info->region.width,(double) nexus_info->region.height,(double)
4535 nexus_info->region.x,(double) nexus_info->region.y);
4540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4544 + R e a d P i x e l C a c h e P i x e l s %
4548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4550 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4553 % The format of the ReadPixelCachePixels() method is:
4555 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4556 % NexusInfo *nexus_info,ExceptionInfo *exception)
4558 % A description of each parameter follows:
4560 % o cache_info: the pixel cache.
4562 % o nexus_info: the cache nexus to read the pixels.
4564 % o exception: return any errors or warnings in this structure.
4567 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4568 NexusInfo *nexus_info,ExceptionInfo *exception)
4587 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4589 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4590 nexus_info->region.x;
4591 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
4593 rows=nexus_info->region.height;
4595 q=nexus_info->pixels;
4596 switch (cache_info->type)
4605 Read pixels from memory.
4607 if ((cache_info->columns == nexus_info->region.width) &&
4608 (extent == (MagickSizeType) ((size_t) extent)))
4613 p=cache_info->pixels+offset*cache_info->number_channels;
4614 for (y=0; y < (ssize_t) rows; y++)
4616 (void) memcpy(q,p,(size_t) length);
4617 p+=cache_info->number_channels*cache_info->columns;
4618 q+=cache_info->number_channels*nexus_info->region.width;
4625 Read pixels from disk.
4627 LockSemaphoreInfo(cache_info->file_semaphore);
4628 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4630 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4631 cache_info->cache_filename);
4632 UnlockSemaphoreInfo(cache_info->file_semaphore);
4633 return(MagickFalse);
4635 if ((cache_info->columns == nexus_info->region.width) &&
4636 (extent <= MagickMaxBufferExtent))
4641 for (y=0; y < (ssize_t) rows; y++)
4643 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4644 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4645 if ((MagickSizeType) count != length)
4647 offset+=cache_info->columns;
4648 q+=cache_info->number_channels*nexus_info->region.width;
4650 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4651 (void) ClosePixelCacheOnDisk(cache_info);
4652 UnlockSemaphoreInfo(cache_info->file_semaphore);
4653 if (y < (ssize_t) rows)
4655 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4656 cache_info->cache_filename);
4657 return(MagickFalse);
4661 case DistributedCache:
4670 Read pixels from distributed cache.
4672 LockSemaphoreInfo(cache_info->file_semaphore);
4673 region=nexus_info->region;
4676 for (y=0; y < (ssize_t) rows; y++)
4678 status=ReadDistributePixelCachePixels(cache_info->server_info,®ion,
4679 length,(unsigned char *) q);
4680 if (status == MagickFalse)
4682 q+=cache_info->number_channels*nexus_info->region.width;
4685 UnlockSemaphoreInfo(cache_info->file_semaphore);
4686 if (status == MagickFalse)
4688 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4689 cache_info->cache_filename);
4690 return(MagickFalse);
4697 if ((cache_info->debug != MagickFalse) &&
4698 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4699 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4700 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4701 nexus_info->region.width,(double) nexus_info->region.height,(double)
4702 nexus_info->region.x,(double) nexus_info->region.y);
4707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4711 + R e f e r e n c e P i x e l C a c h e %
4715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4717 % ReferencePixelCache() increments the reference count associated with the
4718 % pixel cache returning a pointer to the cache.
4720 % The format of the ReferencePixelCache method is:
4722 % Cache ReferencePixelCache(Cache cache_info)
4724 % A description of each parameter follows:
4726 % o cache_info: the pixel cache.
4729 MagickPrivate Cache ReferencePixelCache(Cache cache)
4734 assert(cache != (Cache *) NULL);
4735 cache_info=(CacheInfo *) cache;
4736 assert(cache_info->signature == MagickSignature);
4737 LockSemaphoreInfo(cache_info->semaphore);
4738 cache_info->reference_count++;
4739 UnlockSemaphoreInfo(cache_info->semaphore);
4744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4748 + S e t P i x e l C a c h e M e t h o d s %
4752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4754 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4756 % The format of the SetPixelCacheMethods() method is:
4758 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4760 % A description of each parameter follows:
4762 % o cache: the pixel cache.
4764 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4767 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4772 GetOneAuthenticPixelFromHandler
4773 get_one_authentic_pixel_from_handler;
4775 GetOneVirtualPixelFromHandler
4776 get_one_virtual_pixel_from_handler;
4779 Set cache pixel methods.
4781 assert(cache != (Cache) NULL);
4782 assert(cache_methods != (CacheMethods *) NULL);
4783 cache_info=(CacheInfo *) cache;
4784 assert(cache_info->signature == MagickSignature);
4785 if (cache_info->debug != MagickFalse)
4786 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4787 cache_info->filename);
4788 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4789 cache_info->methods.get_virtual_pixel_handler=
4790 cache_methods->get_virtual_pixel_handler;
4791 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4792 cache_info->methods.destroy_pixel_handler=
4793 cache_methods->destroy_pixel_handler;
4794 if (cache_methods->get_virtual_metacontent_from_handler !=
4795 (GetVirtualMetacontentFromHandler) NULL)
4796 cache_info->methods.get_virtual_metacontent_from_handler=
4797 cache_methods->get_virtual_metacontent_from_handler;
4798 if (cache_methods->get_authentic_pixels_handler !=
4799 (GetAuthenticPixelsHandler) NULL)
4800 cache_info->methods.get_authentic_pixels_handler=
4801 cache_methods->get_authentic_pixels_handler;
4802 if (cache_methods->queue_authentic_pixels_handler !=
4803 (QueueAuthenticPixelsHandler) NULL)
4804 cache_info->methods.queue_authentic_pixels_handler=
4805 cache_methods->queue_authentic_pixels_handler;
4806 if (cache_methods->sync_authentic_pixels_handler !=
4807 (SyncAuthenticPixelsHandler) NULL)
4808 cache_info->methods.sync_authentic_pixels_handler=
4809 cache_methods->sync_authentic_pixels_handler;
4810 if (cache_methods->get_authentic_pixels_from_handler !=
4811 (GetAuthenticPixelsFromHandler) NULL)
4812 cache_info->methods.get_authentic_pixels_from_handler=
4813 cache_methods->get_authentic_pixels_from_handler;
4814 if (cache_methods->get_authentic_metacontent_from_handler !=
4815 (GetAuthenticMetacontentFromHandler) NULL)
4816 cache_info->methods.get_authentic_metacontent_from_handler=
4817 cache_methods->get_authentic_metacontent_from_handler;
4818 get_one_virtual_pixel_from_handler=
4819 cache_info->methods.get_one_virtual_pixel_from_handler;
4820 if (get_one_virtual_pixel_from_handler !=
4821 (GetOneVirtualPixelFromHandler) NULL)
4822 cache_info->methods.get_one_virtual_pixel_from_handler=
4823 cache_methods->get_one_virtual_pixel_from_handler;
4824 get_one_authentic_pixel_from_handler=
4825 cache_methods->get_one_authentic_pixel_from_handler;
4826 if (get_one_authentic_pixel_from_handler !=
4827 (GetOneAuthenticPixelFromHandler) NULL)
4828 cache_info->methods.get_one_authentic_pixel_from_handler=
4829 cache_methods->get_one_authentic_pixel_from_handler;
4833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4837 + S e t P i x e l C a c h e N e x u s P i x e l s %
4841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4843 % SetPixelCacheNexusPixels() defines the region of the cache for the
4844 % specified cache nexus.
4846 % The format of the SetPixelCacheNexusPixels() method is:
4848 % Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4849 % const RectangleInfo *region,NexusInfo *nexus_info,
4850 % ExceptionInfo *exception)
4852 % A description of each parameter follows:
4854 % o image: the image.
4856 % o mode: ReadMode, WriteMode, or IOMode.
4858 % o region: A pointer to the RectangleInfo structure that defines the
4859 % region of this particular cache nexus.
4861 % o nexus_info: the cache nexus to set.
4863 % o exception: return any errors or warnings in this structure.
4867 static inline MagickBooleanType AcquireCacheNexusPixels(
4868 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4869 ExceptionInfo *exception)
4871 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4872 return(MagickFalse);
4873 nexus_info->mapped=MagickFalse;
4874 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4875 (size_t) nexus_info->length));
4876 if (nexus_info->cache == (Quantum *) NULL)
4878 nexus_info->mapped=MagickTrue;
4879 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4880 nexus_info->length);
4882 if (nexus_info->cache == (Quantum *) NULL)
4884 (void) ThrowMagickException(exception,GetMagickModule(),
4885 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4886 cache_info->filename);
4887 return(MagickFalse);
4892 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4895 if (mode == ReadMode)
4897 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4900 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4903 static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4904 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4916 cache_info=(CacheInfo *) image->cache;
4917 assert(cache_info->signature == MagickSignature);
4918 if (cache_info->type == UndefinedCache)
4919 return((Quantum *) NULL);
4920 nexus_info->region=(*region);
4921 if ((cache_info->type == MemoryCache) || (cache_info->type == MapCache))
4927 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4928 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4929 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4930 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4931 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4932 ((nexus_info->region.width == cache_info->columns) ||
4933 ((nexus_info->region.width % cache_info->columns) == 0)))))
4939 Pixels are accessed directly from memory.
4941 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4942 nexus_info->region.x;
4943 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4945 nexus_info->metacontent=(void *) NULL;
4946 if (cache_info->metacontent_extent != 0)
4947 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4948 offset*cache_info->metacontent_extent;
4949 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4950 return(nexus_info->pixels);
4954 Pixels are stored in a cache region until they are synced to the cache.
4956 number_pixels=(MagickSizeType) nexus_info->region.width*
4957 nexus_info->region.height;
4958 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4959 if (cache_info->metacontent_extent != 0)
4960 length+=number_pixels*cache_info->metacontent_extent;
4961 if (nexus_info->cache == (Quantum *) NULL)
4963 nexus_info->length=length;
4964 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4965 if (status == MagickFalse)
4967 nexus_info->length=0;
4968 return((Quantum *) NULL);
4972 if (nexus_info->length != length)
4974 RelinquishCacheNexusPixels(nexus_info);
4975 nexus_info->length=length;
4976 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4977 if (status == MagickFalse)
4979 nexus_info->length=0;
4980 return((Quantum *) NULL);
4983 nexus_info->pixels=nexus_info->cache;
4984 nexus_info->metacontent=(void *) NULL;
4985 if (cache_info->metacontent_extent != 0)
4986 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4987 cache_info->number_channels);
4988 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4989 return(nexus_info->pixels);
4993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4997 % 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 %
5001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5003 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5004 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5005 % access that is outside the boundaries of the image cache.
5007 % The format of the SetPixelCacheVirtualMethod() method is:
5009 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5010 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5012 % A description of each parameter follows:
5014 % o image: the image.
5016 % o virtual_pixel_method: choose the type of virtual pixel.
5018 % o exception: return any errors or warnings in this structure.
5022 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
5023 ExceptionInfo *exception)
5037 assert(image != (Image *) NULL);
5038 assert(image->signature == MagickSignature);
5039 if (image->debug != MagickFalse)
5040 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5041 assert(image->cache != (Cache) NULL);
5042 cache_info=(CacheInfo *) image->cache;
5043 assert(cache_info->signature == MagickSignature);
5044 image->alpha_trait=BlendPixelTrait;
5046 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
5047 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5048 #pragma omp parallel for schedule(static,4) shared(status) \
5049 magick_threads(image,image,1,1)
5051 for (y=0; y < (ssize_t) image->rows; y++)
5059 if (status == MagickFalse)
5061 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5062 if (q == (Quantum *) NULL)
5067 for (x=0; x < (ssize_t) image->columns; x++)
5069 SetPixelAlpha(image,alpha,q);
5070 q+=GetPixelChannels(image);
5072 status=SyncCacheViewAuthenticPixels(image_view,exception);
5074 image_view=DestroyCacheView(image_view);
5078 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5079 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5087 assert(image != (Image *) NULL);
5088 assert(image->signature == MagickSignature);
5089 if (image->debug != MagickFalse)
5090 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5091 assert(image->cache != (Cache) NULL);
5092 cache_info=(CacheInfo *) image->cache;
5093 assert(cache_info->signature == MagickSignature);
5094 method=cache_info->virtual_pixel_method;
5095 cache_info->virtual_pixel_method=virtual_pixel_method;
5096 if ((image->columns != 0) && (image->rows != 0))
5097 switch (virtual_pixel_method)
5099 case BackgroundVirtualPixelMethod:
5101 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
5102 (image->alpha_trait != BlendPixelTrait))
5103 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5104 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
5105 (IsGrayColorspace(image->colorspace) != MagickFalse))
5106 (void) TransformImageColorspace(image,RGBColorspace,exception);
5109 case TransparentVirtualPixelMethod:
5111 if (image->alpha_trait != BlendPixelTrait)
5112 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5126 + 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 %
5130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5132 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5133 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5134 % is synced, otherwise MagickFalse.
5136 % The format of the SyncAuthenticPixelCacheNexus() method is:
5138 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5139 % NexusInfo *nexus_info,ExceptionInfo *exception)
5141 % A description of each parameter follows:
5143 % o image: the image.
5145 % o nexus_info: the cache nexus to sync.
5147 % o exception: return any errors or warnings in this structure.
5150 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5151 NexusInfo *nexus_info,ExceptionInfo *exception)
5160 Transfer pixels to the cache.
5162 assert(image != (Image *) NULL);
5163 assert(image->signature == MagickSignature);
5164 if (image->cache == (Cache) NULL)
5165 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5166 cache_info=(CacheInfo *) image->cache;
5167 assert(cache_info->signature == MagickSignature);
5168 if (cache_info->type == UndefinedCache)
5169 return(MagickFalse);
5170 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5172 assert(cache_info->signature == MagickSignature);
5173 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5174 if ((cache_info->metacontent_extent != 0) &&
5175 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5176 return(MagickFalse);
5181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5185 + S y n c A u t h e n t i c P i x e l C a c h e %
5189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5191 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5192 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5193 % otherwise MagickFalse.
5195 % The format of the SyncAuthenticPixelsCache() method is:
5197 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5198 % ExceptionInfo *exception)
5200 % A description of each parameter follows:
5202 % o image: the image.
5204 % o exception: return any errors or warnings in this structure.
5207 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5208 ExceptionInfo *exception)
5214 id = GetOpenMPThreadId();
5219 assert(image != (Image *) NULL);
5220 assert(image->signature == MagickSignature);
5221 assert(image->cache != (Cache) NULL);
5222 cache_info=(CacheInfo *) image->cache;
5223 assert(cache_info->signature == MagickSignature);
5224 assert(id < (int) cache_info->number_threads);
5225 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5235 % S y n c A u t h e n t i c P i x e l s %
5239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5241 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5242 % The method returns MagickTrue if the pixel region is flushed, otherwise
5245 % The format of the SyncAuthenticPixels() method is:
5247 % MagickBooleanType SyncAuthenticPixels(Image *image,
5248 % ExceptionInfo *exception)
5250 % A description of each parameter follows:
5252 % o image: the image.
5254 % o exception: return any errors or warnings in this structure.
5257 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5258 ExceptionInfo *exception)
5264 id = GetOpenMPThreadId();
5269 assert(image != (Image *) NULL);
5270 assert(image->signature == MagickSignature);
5271 assert(image->cache != (Cache) NULL);
5272 cache_info=(CacheInfo *) image->cache;
5273 assert(cache_info->signature == MagickSignature);
5274 if (cache_info->methods.sync_authentic_pixels_handler !=
5275 (SyncAuthenticPixelsHandler) NULL)
5277 status=cache_info->methods.sync_authentic_pixels_handler(image,
5281 assert(id < (int) cache_info->number_threads);
5282 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5292 + S y n c I m a g e P i x e l C a c h e %
5296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5298 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5299 % The method returns MagickTrue if the pixel region is flushed, otherwise
5302 % The format of the SyncImagePixelCache() method is:
5304 % MagickBooleanType SyncImagePixelCache(Image *image,
5305 % ExceptionInfo *exception)
5307 % A description of each parameter follows:
5309 % o image: the image.
5311 % o exception: return any errors or warnings in this structure.
5314 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5315 ExceptionInfo *exception)
5320 assert(image != (Image *) NULL);
5321 assert(exception != (ExceptionInfo *) NULL);
5322 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5323 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5331 + 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 %
5335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5337 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5338 % of the pixel cache.
5340 % The format of the WritePixelCacheMetacontent() method is:
5342 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5343 % NexusInfo *nexus_info,ExceptionInfo *exception)
5345 % A description of each parameter follows:
5347 % o cache_info: the pixel cache.
5349 % o nexus_info: the cache nexus to write the meta-content.
5351 % o exception: return any errors or warnings in this structure.
5354 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5355 NexusInfo *nexus_info,ExceptionInfo *exception)
5365 register const unsigned char
5374 if (cache_info->metacontent_extent == 0)
5375 return(MagickFalse);
5376 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5378 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5379 nexus_info->region.x;
5380 length=(MagickSizeType) nexus_info->region.width*
5381 cache_info->metacontent_extent;
5382 rows=nexus_info->region.height;
5383 extent=(MagickSizeType) length*rows;
5384 p=(unsigned char *) nexus_info->metacontent;
5385 switch (cache_info->type)
5390 register unsigned char
5394 Write associated pixels to memory.
5396 if ((cache_info->columns == nexus_info->region.width) &&
5397 (extent == (MagickSizeType) ((size_t) extent)))
5402 q=(unsigned char *) cache_info->metacontent+offset*
5403 cache_info->metacontent_extent;
5404 for (y=0; y < (ssize_t) rows; y++)
5406 (void) memcpy(q,p,(size_t) length);
5407 p+=nexus_info->region.width*cache_info->metacontent_extent;
5408 q+=cache_info->columns*cache_info->metacontent_extent;
5415 Write associated pixels to disk.
5417 LockSemaphoreInfo(cache_info->file_semaphore);
5418 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5420 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5421 cache_info->cache_filename);
5422 UnlockSemaphoreInfo(cache_info->file_semaphore);
5423 return(MagickFalse);
5425 if ((cache_info->columns == nexus_info->region.width) &&
5426 (extent <= MagickMaxBufferExtent))
5431 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5432 for (y=0; y < (ssize_t) rows; y++)
5434 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5435 cache_info->number_channels*sizeof(Quantum)+offset*
5436 cache_info->metacontent_extent,length,(const unsigned char *) p);
5437 if ((MagickSizeType) count != length)
5439 p+=cache_info->metacontent_extent*nexus_info->region.width;
5440 offset+=cache_info->columns;
5442 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5443 (void) ClosePixelCacheOnDisk(cache_info);
5444 UnlockSemaphoreInfo(cache_info->file_semaphore);
5445 if (y < (ssize_t) rows)
5447 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5448 cache_info->cache_filename);
5449 return(MagickFalse);
5453 case DistributedCache:
5462 Write metacontent to distributed cache.
5464 LockSemaphoreInfo(cache_info->file_semaphore);
5465 region=nexus_info->region;
5468 for (y=0; y < (ssize_t) rows; y++)
5470 status=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5471 length,(const unsigned char *) p);
5472 if (status == MagickFalse)
5474 p+=cache_info->metacontent_extent*nexus_info->region.width;
5477 UnlockSemaphoreInfo(cache_info->file_semaphore);
5478 if (status == MagickFalse)
5480 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5481 cache_info->cache_filename);
5482 return(MagickFalse);
5489 if ((cache_info->debug != MagickFalse) &&
5490 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5491 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5492 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5493 nexus_info->region.width,(double) nexus_info->region.height,(double)
5494 nexus_info->region.x,(double) nexus_info->region.y);
5499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5503 + W r i t e C a c h e P i x e l s %
5507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5509 % WritePixelCachePixels() writes image pixels to the specified region of the
5512 % The format of the WritePixelCachePixels() method is:
5514 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5515 % NexusInfo *nexus_info,ExceptionInfo *exception)
5517 % A description of each parameter follows:
5519 % o cache_info: the pixel cache.
5521 % o nexus_info: the cache nexus to write the pixels.
5523 % o exception: return any errors or warnings in this structure.
5526 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5527 NexusInfo *nexus_info,ExceptionInfo *exception)
5537 register const Quantum
5546 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5548 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5549 nexus_info->region.x;
5550 length=(MagickSizeType) cache_info->number_channels*nexus_info->region.width*
5552 rows=nexus_info->region.height;
5554 p=nexus_info->pixels;
5555 switch (cache_info->type)
5564 Write pixels to memory.
5566 if ((cache_info->columns == nexus_info->region.width) &&
5567 (extent == (MagickSizeType) ((size_t) extent)))
5572 q=cache_info->pixels+offset*cache_info->number_channels;
5573 for (y=0; y < (ssize_t) rows; y++)
5575 (void) memcpy(q,p,(size_t) length);
5576 p+=cache_info->number_channels*nexus_info->region.width;
5577 q+=cache_info->columns*cache_info->number_channels;
5584 Write pixels to disk.
5586 LockSemaphoreInfo(cache_info->file_semaphore);
5587 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5589 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5590 cache_info->cache_filename);
5591 UnlockSemaphoreInfo(cache_info->file_semaphore);
5592 return(MagickFalse);
5594 if ((cache_info->columns == nexus_info->region.width) &&
5595 (extent <= MagickMaxBufferExtent))
5600 for (y=0; y < (ssize_t) rows; y++)
5602 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5603 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5605 if ((MagickSizeType) count != length)
5607 p+=cache_info->number_channels*nexus_info->region.width;
5608 offset+=cache_info->columns;
5610 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5611 (void) ClosePixelCacheOnDisk(cache_info);
5612 UnlockSemaphoreInfo(cache_info->file_semaphore);
5613 if (y < (ssize_t) rows)
5615 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5616 cache_info->cache_filename);
5617 return(MagickFalse);
5621 case DistributedCache:
5630 Write pixels to distributed cache.
5632 LockSemaphoreInfo(cache_info->file_semaphore);
5633 region=nexus_info->region;
5636 for (y=0; y < (ssize_t) rows; y++)
5638 status=WriteDistributePixelCachePixels(cache_info->server_info,®ion,
5639 length,(const unsigned char *) p);
5640 if (status == MagickFalse)
5642 p+=cache_info->number_channels*nexus_info->region.width;
5645 UnlockSemaphoreInfo(cache_info->file_semaphore);
5646 if (status == MagickFalse)
5648 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5649 cache_info->cache_filename);
5650 return(MagickFalse);
5657 if ((cache_info->debug != MagickFalse) &&
5658 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5659 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5660 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5661 nexus_info->region.width,(double) nexus_info->region.height,(double)
5662 nexus_info->region.x,(double) nexus_info->region.y);