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-2012 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/composite-private.h"
50 #include "MagickCore/exception.h"
51 #include "MagickCore/exception-private.h"
52 #include "MagickCore/geometry.h"
53 #include "MagickCore/list.h"
54 #include "MagickCore/log.h"
55 #include "MagickCore/magick.h"
56 #include "MagickCore/memory_.h"
57 #include "MagickCore/pixel.h"
58 #include "MagickCore/pixel-accessor.h"
59 #include "MagickCore/policy.h"
60 #include "MagickCore/quantum.h"
61 #include "MagickCore/random_.h"
62 #include "MagickCore/resource_.h"
63 #include "MagickCore/semaphore.h"
64 #include "MagickCore/splay-tree.h"
65 #include "MagickCore/string_.h"
66 #include "MagickCore/string-private.h"
67 #include "MagickCore/thread-private.h"
68 #include "MagickCore/utility.h"
69 #include "MagickCore/utility-private.h"
70 #if defined(MAGICKCORE_ZLIB_DELEGATE)
77 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
78 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
79 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
84 typedef struct _MagickModulo
114 Forward declarations.
116 #if defined(__cplusplus) || defined(c_plusplus)
121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
123 *GetVirtualPixelsCache(const Image *);
126 *GetVirtualMetacontentFromCache(const Image *);
128 static MagickBooleanType
129 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
130 Quantum *,ExceptionInfo *),
131 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
132 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
133 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
134 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
136 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
137 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
138 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
141 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
143 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
144 const size_t,ExceptionInfo *),
145 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
148 #if defined(__cplusplus) || defined(c_plusplus)
155 static volatile MagickBooleanType
156 instantiate_cache = MagickFalse;
159 *cache_semaphore = (SemaphoreInfo *) NULL;
162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166 + A c q u i r e P i x e l C a c h e %
170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 % AcquirePixelCache() acquires a pixel cache.
174 % The format of the AcquirePixelCache() method is:
176 % Cache AcquirePixelCache(const size_t number_threads)
178 % A description of each parameter follows:
180 % o number_threads: the number of nexus threads.
183 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
188 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
193 cache_info->mode=IOMode;
194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
203 cache_info->semaphore=AllocateSemaphoreInfo();
204 cache_info->reference_count=1;
205 cache_info->disk_semaphore=AllocateSemaphoreInfo();
206 cache_info->debug=IsEventLogging();
207 cache_info->signature=MagickSignature;
208 return((Cache ) cache_info);
212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216 % A c q u i r e P i x e l C a c h e N e x u s %
220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
224 % The format of the AcquirePixelCacheNexus method is:
226 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
228 % A description of each parameter follows:
230 % o number_threads: the number of nexus threads.
233 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
241 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
242 sizeof(*nexus_info));
243 if (nexus_info == (NexusInfo **) NULL)
244 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
245 for (i=0; i < (ssize_t) number_threads; i++)
247 nexus_info[i]=(NexusInfo *) AcquireQuantumMemory(1,sizeof(**nexus_info));
248 if (nexus_info[i] == (NexusInfo *) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
250 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
251 nexus_info[i]->signature=MagickSignature;
257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261 + A c q u i r e P i x e l C a c h e P i x e l s %
265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267 % AcquirePixelCachePixels() returns the pixels associated with the specified
270 % The format of the AcquirePixelCachePixels() method is:
272 % const void *AcquirePixelCachePixels(const Image *image,
273 % MagickSizeType *length,ExceptionInfo *exception)
275 % A description of each parameter follows:
277 % o image: the image.
279 % o length: the pixel cache length.
281 % o exception: return any errors or warnings in this structure.
284 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
285 MagickSizeType *length,ExceptionInfo *exception)
290 assert(image != (const Image *) NULL);
291 assert(image->signature == MagickSignature);
292 assert(exception != (ExceptionInfo *) NULL);
293 assert(exception->signature == MagickSignature);
294 assert(image->cache != (Cache) NULL);
295 cache_info=(CacheInfo *) image->cache;
296 assert(cache_info->signature == MagickSignature);
298 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
299 return((const void *) NULL);
300 *length=cache_info->length;
301 return((const void *) cache_info->pixels);
305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309 + C a c h e C o m p o n e n t G e n e s i s %
313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
315 % CacheComponentGenesis() instantiates the cache component.
317 % The format of the CacheComponentGenesis method is:
319 % MagickBooleanType CacheComponentGenesis(void)
322 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
324 AcquireSemaphoreInfo(&cache_semaphore);
329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333 + C a c h e C o m p o n e n t T e r m i n u s %
337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339 % CacheComponentTerminus() destroys the cache component.
341 % The format of the CacheComponentTerminus() method is:
343 % CacheComponentTerminus(void)
346 MagickPrivate void CacheComponentTerminus(void)
348 if (cache_semaphore == (SemaphoreInfo *) NULL)
349 AcquireSemaphoreInfo(&cache_semaphore);
350 LockSemaphoreInfo(cache_semaphore);
351 instantiate_cache=MagickFalse;
352 UnlockSemaphoreInfo(cache_semaphore);
353 DestroySemaphoreInfo(&cache_semaphore);
357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
361 + C l o n e P i x e l C a c h e %
365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
367 % ClonePixelCache() clones a pixel cache.
369 % The format of the ClonePixelCache() method is:
371 % Cache ClonePixelCache(const Cache cache)
373 % A description of each parameter follows:
375 % o cache: the pixel cache.
378 MagickPrivate Cache ClonePixelCache(const Cache cache)
386 assert(cache != NULL);
387 cache_info=(const CacheInfo *) cache;
388 assert(cache_info->signature == MagickSignature);
389 if (cache_info->debug != MagickFalse)
390 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
391 cache_info->filename);
392 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
393 if (clone_info == (Cache) NULL)
394 return((Cache) NULL);
395 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
396 return((Cache ) clone_info);
400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404 + C l o n e P i x e l C a c h e P i x e l s %
408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
409 % ClonePixelCachePixels() clones the source pixel cache to the destination
412 % The format of the ClonePixelCachePixels() method is:
414 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
415 % CacheInfo *source_info,ExceptionInfo *exception)
417 % A description of each parameter follows:
419 % o cache_info: the pixel cache.
421 % o source_info: the source pixel cache.
423 % o exception: return any errors or warnings in this structure.
427 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
433 LockSemaphoreInfo(cache_info->disk_semaphore);
434 if (cache_info->file != -1)
436 status=close(cache_info->file);
437 cache_info->file=(-1);
438 RelinquishMagickResource(FileResource,1);
440 UnlockSemaphoreInfo(cache_info->disk_semaphore);
441 return(status == -1 ? MagickFalse : MagickTrue);
444 static inline MagickSizeType MagickMax(const MagickSizeType x,
445 const MagickSizeType y)
452 static inline MagickSizeType MagickMin(const MagickSizeType x,
453 const MagickSizeType y)
460 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
467 Open pixel cache on disk.
469 LockSemaphoreInfo(cache_info->disk_semaphore);
470 if (cache_info->file != -1)
472 UnlockSemaphoreInfo(cache_info->disk_semaphore);
473 return(MagickTrue); /* cache already open */
475 if (*cache_info->cache_filename == '\0')
476 file=AcquireUniqueFileResource(cache_info->cache_filename);
482 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
487 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
488 O_BINARY | O_EXCL,S_MODE);
490 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
496 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
499 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
505 UnlockSemaphoreInfo(cache_info->disk_semaphore);
508 (void) AcquireMagickResource(FileResource,1);
509 cache_info->file=file;
510 cache_info->mode=mode;
511 cache_info->timestamp=time(0);
512 UnlockSemaphoreInfo(cache_info->disk_semaphore);
516 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
517 const MagickOffsetType offset,const MagickSizeType length,
518 unsigned char *restrict buffer)
520 register MagickOffsetType
526 cache_info->timestamp=time(0);
527 #if !defined(MAGICKCORE_HAVE_PREAD)
528 LockSemaphoreInfo(cache_info->disk_semaphore);
529 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
531 UnlockSemaphoreInfo(cache_info->disk_semaphore);
532 return((MagickOffsetType) -1);
536 for (i=0; i < (MagickOffsetType) length; i+=count)
538 #if !defined(MAGICKCORE_HAVE_PREAD)
539 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
540 (MagickSizeType) SSIZE_MAX));
542 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
543 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
554 #if !defined(MAGICKCORE_HAVE_PREAD)
555 UnlockSemaphoreInfo(cache_info->disk_semaphore);
560 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
561 const MagickOffsetType offset,const MagickSizeType length,
562 const unsigned char *restrict buffer)
564 register MagickOffsetType
570 cache_info->timestamp=time(0);
571 #if !defined(MAGICKCORE_HAVE_PWRITE)
572 LockSemaphoreInfo(cache_info->disk_semaphore);
573 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
575 UnlockSemaphoreInfo(cache_info->disk_semaphore);
576 return((MagickOffsetType) -1);
580 for (i=0; i < (MagickOffsetType) length; i+=count)
582 #if !defined(MAGICKCORE_HAVE_PWRITE)
583 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
584 (MagickSizeType) SSIZE_MAX));
586 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
587 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
598 #if !defined(MAGICKCORE_HAVE_PWRITE)
599 UnlockSemaphoreInfo(cache_info->disk_semaphore);
604 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
605 CacheInfo *cache_info,ExceptionInfo *exception)
610 register MagickOffsetType
620 Clone pixel cache (both caches on disk).
622 if (cache_info->debug != MagickFalse)
623 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
624 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
626 if (blob == (unsigned char *) NULL)
628 (void) ThrowMagickException(exception,GetMagickModule(),
629 ResourceLimitError,"MemoryAllocationFailed","`%s'",
630 cache_info->filename);
633 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
635 blob=(unsigned char *) RelinquishMagickMemory(blob);
636 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
637 cache_info->cache_filename);
640 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
642 (void) ClosePixelCacheOnDisk(cache_info);
643 blob=(unsigned char *) RelinquishMagickMemory(blob);
644 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
645 clone_info->cache_filename);
649 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
651 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
652 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
656 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
657 cache_info->cache_filename);
660 length=(size_t) count;
661 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
662 if ((MagickSizeType) count != length)
664 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
665 clone_info->cache_filename);
669 (void) ClosePixelCacheOnDisk(clone_info);
670 (void) ClosePixelCacheOnDisk(cache_info);
671 blob=(unsigned char *) RelinquishMagickMemory(blob);
672 if (i < (MagickOffsetType) cache_info->length)
677 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
678 CacheInfo *cache_info,ExceptionInfo *exception)
683 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
686 Clone pixel cache (both caches in memory).
688 if (cache_info->debug != MagickFalse)
689 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
690 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
694 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
697 Clone pixel cache (one cache on disk, one in memory).
699 if (cache_info->debug != MagickFalse)
700 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
701 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
703 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
704 cache_info->cache_filename);
707 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
708 cache_info->length,(unsigned char *) clone_info->pixels);
709 (void) ClosePixelCacheOnDisk(cache_info);
710 if ((MagickSizeType) count != cache_info->length)
712 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
713 cache_info->cache_filename);
718 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
721 Clone pixel cache (one cache on disk, one in memory).
723 if (clone_info->debug != MagickFalse)
724 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
725 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
727 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
728 clone_info->cache_filename);
731 count=WritePixelCacheRegion(clone_info,clone_info->offset,
732 clone_info->length,(unsigned char *) cache_info->pixels);
733 (void) ClosePixelCacheOnDisk(clone_info);
734 if ((MagickSizeType) count != clone_info->length)
736 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
737 clone_info->cache_filename);
743 Clone pixel cache (both caches on disk).
745 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
748 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
749 CacheInfo *cache_info,ExceptionInfo *exception)
762 register unsigned char
775 Clone pixel cache (unoptimized).
777 if (cache_info->debug != MagickFalse)
779 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
780 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
782 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
783 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
785 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
790 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
791 clone_info->number_channels)*sizeof(Quantum),MagickMax(
792 cache_info->metacontent_extent,clone_info->metacontent_extent));
793 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
794 if (blob == (unsigned char *) NULL)
796 (void) ThrowMagickException(exception,GetMagickModule(),
797 ResourceLimitError,"MemoryAllocationFailed","`%s'",
798 cache_info->filename);
801 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
804 if (cache_info->type == DiskCache)
806 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
808 blob=(unsigned char *) RelinquishMagickMemory(blob);
809 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
810 cache_info->cache_filename);
813 cache_offset=cache_info->offset;
815 if (clone_info->type == DiskCache)
817 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
819 blob=(unsigned char *) RelinquishMagickMemory(blob);
820 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
821 clone_info->cache_filename);
824 clone_offset=clone_info->offset;
827 Clone pixel channels.
831 for (y=0; y < (ssize_t) cache_info->rows; y++)
833 for (x=0; x < (ssize_t) cache_info->columns; x++)
839 Read a set of pixel channels.
841 length=cache_info->number_channels*sizeof(Quantum);
842 if (cache_info->type != DiskCache)
843 p=(unsigned char *) cache_info->pixels+cache_offset;
846 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
847 if ((MagickSizeType) count != length)
853 cache_offset+=length;
854 if ((y < (ssize_t) clone_info->rows) &&
855 (x < (ssize_t) clone_info->columns))
856 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
868 Write a set of pixel channels.
870 channel=clone_info->channel_map[i].channel;
871 traits=cache_info->channel_map[channel].traits;
872 if (traits == UndefinedPixelTrait)
874 clone_offset+=sizeof(Quantum);
877 offset=cache_info->channel_map[channel].offset;
878 if (clone_info->type != DiskCache)
879 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
880 offset*sizeof(Quantum),sizeof(Quantum));
883 count=WritePixelCacheRegion(clone_info,clone_offset,
884 sizeof(Quantum),p+offset*sizeof(Quantum));
885 if ((MagickSizeType) count != sizeof(Quantum))
891 clone_offset+=sizeof(Quantum);
894 length=clone_info->number_channels*sizeof(Quantum);
895 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
896 for ( ; x < (ssize_t) clone_info->columns; x++)
899 Set remaining columns as undefined.
901 if (clone_info->type != DiskCache)
902 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
906 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
907 if ((MagickSizeType) count != length)
913 clone_offset+=length;
916 length=clone_info->number_channels*sizeof(Quantum);
917 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
918 for ( ; y < (ssize_t) clone_info->rows; y++)
921 Set remaining rows as undefined.
923 for (x=0; x < (ssize_t) clone_info->columns; x++)
925 if (clone_info->type != DiskCache)
926 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
930 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
931 if ((MagickSizeType) count != length)
937 clone_offset+=length;
940 if ((cache_info->metacontent_extent != 0) ||
941 (clone_info->metacontent_extent != 0))
946 for (y=0; y < (ssize_t) cache_info->rows; y++)
948 for (x=0; x < (ssize_t) cache_info->columns; x++)
951 Read a set of metacontent.
953 length=cache_info->metacontent_extent;
954 if (cache_info->type != DiskCache)
955 p=(unsigned char *) cache_info->pixels+cache_offset;
958 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
959 if ((MagickSizeType) count != length)
965 cache_offset+=length;
966 if ((y < (ssize_t) clone_info->rows) &&
967 (x < (ssize_t) clone_info->columns))
970 Write a set of metacontent.
972 length=clone_info->metacontent_extent;
973 if (clone_info->type != DiskCache)
974 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
978 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
979 if ((MagickSizeType) count != length)
985 clone_offset+=length;
988 length=clone_info->metacontent_extent;
989 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
990 for ( ; x < (ssize_t) clone_info->columns; x++)
993 Set remaining columns as undefined.
995 if (clone_info->type != DiskCache)
996 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1000 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1001 if ((MagickSizeType) count != length)
1007 clone_offset+=length;
1010 length=clone_info->metacontent_extent;
1011 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1012 for ( ; y < (ssize_t) clone_info->rows; y++)
1015 Set remaining rows as undefined.
1017 for (x=0; x < (ssize_t) clone_info->columns; x++)
1019 if (clone_info->type != DiskCache)
1020 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1024 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1025 if ((MagickSizeType) count != length)
1031 clone_offset+=length;
1035 if (clone_info->type == DiskCache)
1036 (void) ClosePixelCacheOnDisk(clone_info);
1037 if (cache_info->type == DiskCache)
1038 (void) ClosePixelCacheOnDisk(cache_info);
1039 blob=(unsigned char *) RelinquishMagickMemory(blob);
1043 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1044 CacheInfo *cache_info,ExceptionInfo *exception)
1050 if (cache_info->type == PingCache)
1052 p=cache_info->channel_map;
1053 q=clone_info->channel_map;
1054 if ((cache_info->columns == clone_info->columns) &&
1055 (cache_info->rows == clone_info->rows) &&
1056 (cache_info->number_channels == clone_info->number_channels) &&
1057 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1058 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1059 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1060 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1068 + C l o n e P i x e l C a c h e M e t h o d s %
1072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1074 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1077 % The format of the ClonePixelCacheMethods() method is:
1079 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1081 % A description of each parameter follows:
1083 % o clone: Specifies a pointer to a Cache structure.
1085 % o cache: the pixel cache.
1088 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1094 assert(clone != (Cache) NULL);
1095 source_info=(CacheInfo *) clone;
1096 assert(source_info->signature == MagickSignature);
1097 if (source_info->debug != MagickFalse)
1098 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1099 source_info->filename);
1100 assert(cache != (Cache) NULL);
1101 cache_info=(CacheInfo *) cache;
1102 assert(cache_info->signature == MagickSignature);
1103 source_info->methods=cache_info->methods;
1107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1111 + D e s t r o y I m a g e P i x e l C a c h e %
1115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1117 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1119 % The format of the DestroyImagePixelCache() method is:
1121 % void DestroyImagePixelCache(Image *image)
1123 % A description of each parameter follows:
1125 % o image: the image.
1128 static void DestroyImagePixelCache(Image *image)
1130 assert(image != (Image *) NULL);
1131 assert(image->signature == MagickSignature);
1132 if (image->debug != MagickFalse)
1133 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1134 if (image->cache == (void *) NULL)
1136 image->cache=DestroyPixelCache(image->cache);
1140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1144 + D e s t r o y I m a g e P i x e l s %
1148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1150 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1152 % The format of the DestroyImagePixels() method is:
1154 % void DestroyImagePixels(Image *image)
1156 % A description of each parameter follows:
1158 % o image: the image.
1161 MagickExport void DestroyImagePixels(Image *image)
1166 assert(image != (const Image *) NULL);
1167 assert(image->signature == MagickSignature);
1168 if (image->debug != MagickFalse)
1169 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1170 assert(image->cache != (Cache) NULL);
1171 cache_info=(CacheInfo *) image->cache;
1172 assert(cache_info->signature == MagickSignature);
1173 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1175 cache_info->methods.destroy_pixel_handler(image);
1178 image->cache=DestroyPixelCache(image->cache);
1182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1186 + D e s t r o y P i x e l C a c h e %
1190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1194 % The format of the DestroyPixelCache() method is:
1196 % Cache DestroyPixelCache(Cache cache)
1198 % A description of each parameter follows:
1200 % o cache: the pixel cache.
1204 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1206 switch (cache_info->type)
1210 if (cache_info->mapped == MagickFalse)
1211 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
1212 cache_info->pixels);
1214 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1215 (size_t) cache_info->length);
1216 RelinquishMagickResource(MemoryResource,cache_info->length);
1221 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1222 cache_info->length);
1223 RelinquishMagickResource(MapResource,cache_info->length);
1227 if (cache_info->file != -1)
1228 (void) ClosePixelCacheOnDisk(cache_info);
1229 RelinquishMagickResource(DiskResource,cache_info->length);
1235 cache_info->type=UndefinedCache;
1236 cache_info->mapped=MagickFalse;
1237 cache_info->metacontent=(void *) NULL;
1240 MagickPrivate Cache DestroyPixelCache(Cache cache)
1245 assert(cache != (Cache) NULL);
1246 cache_info=(CacheInfo *) cache;
1247 assert(cache_info->signature == MagickSignature);
1248 if (cache_info->debug != MagickFalse)
1249 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1250 cache_info->filename);
1251 LockSemaphoreInfo(cache_info->semaphore);
1252 cache_info->reference_count--;
1253 if (cache_info->reference_count != 0)
1255 UnlockSemaphoreInfo(cache_info->semaphore);
1256 return((Cache) NULL);
1258 UnlockSemaphoreInfo(cache_info->semaphore);
1259 if (cache_info->debug != MagickFalse)
1262 message[MaxTextExtent];
1264 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1265 cache_info->filename);
1266 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1268 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1269 (cache_info->type != DiskCache)))
1270 RelinquishPixelCachePixels(cache_info);
1273 RelinquishPixelCachePixels(cache_info);
1274 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1276 *cache_info->cache_filename='\0';
1277 if (cache_info->nexus_info != (NexusInfo **) NULL)
1278 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1279 cache_info->number_threads);
1280 if (cache_info->random_info != (RandomInfo *) NULL)
1281 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1282 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1283 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1284 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1285 DestroySemaphoreInfo(&cache_info->semaphore);
1286 cache_info->signature=(~MagickSignature);
1287 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1297 + D e s t r o y P i x e l C a c h e N e x u s %
1301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1305 % The format of the DestroyPixelCacheNexus() method is:
1307 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1308 % const size_t number_threads)
1310 % A description of each parameter follows:
1312 % o nexus_info: the nexus to destroy.
1314 % o number_threads: the number of nexus threads.
1318 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1320 if (nexus_info->mapped == MagickFalse)
1321 (void) RelinquishAlignedMemory(nexus_info->cache);
1323 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1324 nexus_info->cache=(Quantum *) NULL;
1325 nexus_info->pixels=(Quantum *) NULL;
1326 nexus_info->metacontent=(void *) NULL;
1327 nexus_info->length=0;
1328 nexus_info->mapped=MagickFalse;
1331 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1332 const size_t number_threads)
1337 assert(nexus_info != (NexusInfo **) NULL);
1338 for (i=0; i < (ssize_t) number_threads; i++)
1340 if (nexus_info[i]->cache != (Quantum *) NULL)
1341 RelinquishCacheNexusPixels(nexus_info[i]);
1342 nexus_info[i]->signature=(~MagickSignature);
1343 nexus_info[i]=(NexusInfo *) RelinquishMagickMemory(nexus_info[i]);
1345 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354 % G e t A u t h e n t i c M e t a c o n t e n t %
1358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1361 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1362 % returned if the associated pixels are not available.
1364 % The format of the GetAuthenticMetacontent() method is:
1366 % void *GetAuthenticMetacontent(const Image *image)
1368 % A description of each parameter follows:
1370 % o image: the image.
1373 MagickExport void *GetAuthenticMetacontent(const Image *image)
1379 id = GetOpenMPThreadId();
1384 assert(image != (const Image *) NULL);
1385 assert(image->signature == MagickSignature);
1386 assert(image->cache != (Cache) NULL);
1387 cache_info=(CacheInfo *) image->cache;
1388 assert(cache_info->signature == MagickSignature);
1389 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1390 (GetAuthenticMetacontentFromHandler) NULL)
1392 metacontent=cache_info->methods.
1393 get_authentic_metacontent_from_handler(image);
1394 return(metacontent);
1396 assert(id < (int) cache_info->number_threads);
1397 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1398 cache_info->nexus_info[id]);
1399 return(metacontent);
1403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1407 + 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 %
1411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1414 % with the last call to QueueAuthenticPixelsCache() or
1415 % GetAuthenticPixelsCache().
1417 % The format of the GetAuthenticMetacontentFromCache() method is:
1419 % void *GetAuthenticMetacontentFromCache(const Image *image)
1421 % A description of each parameter follows:
1423 % o image: the image.
1426 static void *GetAuthenticMetacontentFromCache(const Image *image)
1432 id = GetOpenMPThreadId();
1437 assert(image != (const Image *) NULL);
1438 assert(image->signature == MagickSignature);
1439 assert(image->cache != (Cache) NULL);
1440 cache_info=(CacheInfo *) image->cache;
1441 assert(cache_info->signature == MagickSignature);
1442 assert(id < (int) cache_info->number_threads);
1443 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1444 cache_info->nexus_info[id]);
1445 return(metacontent);
1449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1453 + 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 %
1457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1460 % disk pixel cache as defined by the geometry parameters. A pointer to the
1461 % pixels is returned if the pixels are transferred, otherwise a NULL is
1464 % The format of the GetAuthenticPixelCacheNexus() method is:
1466 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1467 % const ssize_t y,const size_t columns,const size_t rows,
1468 % NexusInfo *nexus_info,ExceptionInfo *exception)
1470 % A description of each parameter follows:
1472 % o image: the image.
1474 % o x,y,columns,rows: These values define the perimeter of a region of
1477 % o nexus_info: the cache nexus to return.
1479 % o exception: return any errors or warnings in this structure.
1483 static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
1484 NexusInfo *nexus_info)
1492 if (cache_info->type == PingCache)
1494 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1495 nexus_info->region.x;
1496 status=nexus_info->pixels == (cache_info->pixels+offset*
1497 cache_info->number_channels) ? MagickTrue : MagickFalse;
1501 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1502 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1503 NexusInfo *nexus_info,ExceptionInfo *exception)
1512 Transfer pixels from the cache.
1514 assert(image != (Image *) NULL);
1515 assert(image->signature == MagickSignature);
1516 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1518 if (q == (Quantum *) NULL)
1519 return((Quantum *) NULL);
1520 cache_info=(CacheInfo *) image->cache;
1521 assert(cache_info->signature == MagickSignature);
1522 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1524 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1525 return((Quantum *) NULL);
1526 if (cache_info->metacontent_extent != 0)
1527 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1528 return((Quantum *) NULL);
1533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1537 + 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 %
1541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1543 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1544 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1546 % The format of the GetAuthenticPixelsFromCache() method is:
1548 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1550 % A description of each parameter follows:
1552 % o image: the image.
1555 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1561 id = GetOpenMPThreadId();
1563 assert(image != (const Image *) NULL);
1564 assert(image->signature == MagickSignature);
1565 assert(image->cache != (Cache) NULL);
1566 cache_info=(CacheInfo *) image->cache;
1567 assert(cache_info->signature == MagickSignature);
1568 assert(id < (int) cache_info->number_threads);
1569 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1577 % G e t A u t h e n t i c P i x e l Q u e u e %
1581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1583 % GetAuthenticPixelQueue() returns the authentic pixels associated
1584 % corresponding with the last call to QueueAuthenticPixels() or
1585 % GetAuthenticPixels().
1587 % The format of the GetAuthenticPixelQueue() method is:
1589 % Quantum *GetAuthenticPixelQueue(const Image image)
1591 % A description of each parameter follows:
1593 % o image: the image.
1596 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1602 id = GetOpenMPThreadId();
1604 assert(image != (const Image *) NULL);
1605 assert(image->signature == MagickSignature);
1606 assert(image->cache != (Cache) NULL);
1607 cache_info=(CacheInfo *) image->cache;
1608 assert(cache_info->signature == MagickSignature);
1609 if (cache_info->methods.get_authentic_pixels_from_handler !=
1610 (GetAuthenticPixelsFromHandler) NULL)
1611 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1612 assert(id < (int) cache_info->number_threads);
1613 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1621 % G e t A u t h e n t i c P i x e l s %
1624 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1626 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1627 % region is successfully accessed, a pointer to a Quantum array
1628 % representing the region is returned, otherwise NULL is returned.
1630 % The returned pointer may point to a temporary working copy of the pixels
1631 % or it may point to the original pixels in memory. Performance is maximized
1632 % if the selected region is part of one row, or one or more full rows, since
1633 % then there is opportunity to access the pixels in-place (without a copy)
1634 % if the image is in memory, or in a memory-mapped file. The returned pointer
1635 % must *never* be deallocated by the user.
1637 % Pixels accessed via the returned pointer represent a simple array of type
1638 % Quantum. If the image has corresponding metacontent,call
1639 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1640 % meta-content corresponding to the region. Once the Quantum array has
1641 % been updated, the changes must be saved back to the underlying image using
1642 % SyncAuthenticPixels() or they may be lost.
1644 % The format of the GetAuthenticPixels() method is:
1646 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1647 % const ssize_t y,const size_t columns,const size_t rows,
1648 % ExceptionInfo *exception)
1650 % A description of each parameter follows:
1652 % o image: the image.
1654 % o x,y,columns,rows: These values define the perimeter of a region of
1657 % o exception: return any errors or warnings in this structure.
1660 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1661 const ssize_t y,const size_t columns,const size_t rows,
1662 ExceptionInfo *exception)
1668 id = GetOpenMPThreadId();
1673 assert(image != (Image *) NULL);
1674 assert(image->signature == MagickSignature);
1675 assert(image->cache != (Cache) NULL);
1676 cache_info=(CacheInfo *) image->cache;
1677 assert(cache_info->signature == MagickSignature);
1678 if (cache_info->methods.get_authentic_pixels_handler !=
1679 (GetAuthenticPixelsHandler) NULL)
1681 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1685 assert(id < (int) cache_info->number_threads);
1686 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1687 cache_info->nexus_info[id],exception);
1692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1696 + G e t A u t h e n t i c P i x e l s C a c h e %
1700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1702 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1703 % as defined by the geometry parameters. A pointer to the pixels is returned
1704 % if the pixels are transferred, otherwise a NULL is returned.
1706 % The format of the GetAuthenticPixelsCache() method is:
1708 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1709 % const ssize_t y,const size_t columns,const size_t rows,
1710 % ExceptionInfo *exception)
1712 % A description of each parameter follows:
1714 % o image: the image.
1716 % o x,y,columns,rows: These values define the perimeter of a region of
1719 % o exception: return any errors or warnings in this structure.
1722 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1723 const ssize_t y,const size_t columns,const size_t rows,
1724 ExceptionInfo *exception)
1730 id = GetOpenMPThreadId();
1735 assert(image != (const Image *) NULL);
1736 assert(image->signature == MagickSignature);
1737 assert(image->cache != (Cache) NULL);
1738 cache_info=(CacheInfo *) image->cache;
1739 if (cache_info == (Cache) NULL)
1740 return((Quantum *) NULL);
1741 assert(cache_info->signature == MagickSignature);
1742 assert(id < (int) cache_info->number_threads);
1743 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1744 cache_info->nexus_info[id],exception);
1749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1753 + G e t I m a g e E x t e n t %
1757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759 % GetImageExtent() returns the extent of the pixels associated corresponding
1760 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1762 % The format of the GetImageExtent() method is:
1764 % MagickSizeType GetImageExtent(const Image *image)
1766 % A description of each parameter follows:
1768 % o image: the image.
1771 MagickExport MagickSizeType GetImageExtent(const Image *image)
1777 id = GetOpenMPThreadId();
1779 assert(image != (Image *) NULL);
1780 assert(image->signature == MagickSignature);
1781 if (image->debug != MagickFalse)
1782 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1783 assert(image->cache != (Cache) NULL);
1784 cache_info=(CacheInfo *) image->cache;
1785 assert(cache_info->signature == MagickSignature);
1786 assert(id < (int) cache_info->number_threads);
1787 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1795 + G e t I m a g e P i x e l C a c h e %
1799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1801 % GetImagePixelCache() ensures that there is only a single reference to the
1802 % pixel cache to be modified, updating the provided cache pointer to point to
1803 % a clone of the original pixel cache if necessary.
1805 % The format of the GetImagePixelCache method is:
1807 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1808 % ExceptionInfo *exception)
1810 % A description of each parameter follows:
1812 % o image: the image.
1814 % o clone: any value other than MagickFalse clones the cache pixels.
1816 % o exception: return any errors or warnings in this structure.
1820 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1830 Does the image match the pixel cache morphology?
1832 cache_info=(CacheInfo *) image->cache;
1833 p=image->channel_map;
1834 q=cache_info->channel_map;
1835 if ((image->storage_class != cache_info->storage_class) ||
1836 (image->colorspace != cache_info->colorspace) ||
1837 (image->matte != cache_info->matte) ||
1838 (image->mask != cache_info->mask) ||
1839 (image->columns != cache_info->columns) ||
1840 (image->rows != cache_info->rows) ||
1841 (image->number_channels != cache_info->number_channels) ||
1842 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1843 (image->metacontent_extent != cache_info->metacontent_extent) ||
1844 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1845 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1846 return(MagickFalse);
1850 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1851 ExceptionInfo *exception)
1860 static MagickSizeType
1866 cache_timestamp = 0;
1869 LockSemaphoreInfo(image->semaphore);
1870 if (cpu_throttle == 0)
1876 Set CPU throttle in milleseconds.
1878 cpu_throttle=MagickResourceInfinity;
1879 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1880 if (limit == (char *) NULL)
1881 limit=GetPolicyValue("throttle");
1882 if (limit != (char *) NULL)
1884 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1885 limit=DestroyString(limit);
1888 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1889 MagickDelay(cpu_throttle);
1890 if (time_limit == 0)
1893 Set the exire time in seconds.
1895 time_limit=GetMagickResourceLimit(TimeResource);
1896 cache_timestamp=time((time_t *) NULL);
1898 if ((time_limit != MagickResourceInfinity) &&
1899 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1900 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1901 assert(image->cache != (Cache) NULL);
1902 cache_info=(CacheInfo *) image->cache;
1903 destroy=MagickFalse;
1904 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1906 LockSemaphoreInfo(cache_info->semaphore);
1907 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1918 clone_image=(*image);
1919 clone_image.semaphore=AllocateSemaphoreInfo();
1920 clone_image.reference_count=1;
1921 clone_image.cache=ClonePixelCache(cache_info);
1922 clone_info=(CacheInfo *) clone_image.cache;
1923 status=OpenPixelCache(&clone_image,IOMode,exception);
1924 if (status != MagickFalse)
1926 if (clone != MagickFalse)
1927 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1928 if (status != MagickFalse)
1930 if (cache_info->mode == ReadMode)
1931 cache_info->nexus_info=(NexusInfo **) NULL;
1933 image->cache=clone_image.cache;
1936 DestroySemaphoreInfo(&clone_image.semaphore);
1938 UnlockSemaphoreInfo(cache_info->semaphore);
1940 if (destroy != MagickFalse)
1941 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1942 if (status != MagickFalse)
1945 Ensure the image matches the pixel cache morphology.
1947 image->taint=MagickTrue;
1948 image->type=UndefinedType;
1949 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1951 status=OpenPixelCache(image,IOMode,exception);
1952 cache_info=(CacheInfo *) image->cache;
1953 if (cache_info->type == DiskCache)
1954 (void) ClosePixelCacheOnDisk(cache_info);
1957 UnlockSemaphoreInfo(image->semaphore);
1958 if (status == MagickFalse)
1959 return((Cache) NULL);
1960 return(image->cache);
1964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1968 % G e t O n e A u t h e n t i c P i x e l %
1972 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1974 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1975 % location. The image background color is returned if an error occurs.
1977 % The format of the GetOneAuthenticPixel() method is:
1979 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1980 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1982 % A description of each parameter follows:
1984 % o image: the image.
1986 % o x,y: These values define the location of the pixel to return.
1988 % o pixel: return a pixel at the specified (x,y) location.
1990 % o exception: return any errors or warnings in this structure.
1993 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1994 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2005 assert(image != (Image *) NULL);
2006 assert(image->signature == MagickSignature);
2007 assert(image->cache != (Cache) NULL);
2008 cache_info=(CacheInfo *) image->cache;
2009 assert(cache_info->signature == MagickSignature);
2010 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2011 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2012 (GetOneAuthenticPixelFromHandler) NULL)
2013 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2015 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2016 if (q == (Quantum *) NULL)
2018 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2019 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2020 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2021 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2022 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2023 return(MagickFalse);
2025 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2030 channel=GetPixelChannelMapChannel(image,i);
2031 pixel[channel]=q[i];
2037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2041 + 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 %
2045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2047 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2048 % location. The image background color is returned if an error occurs.
2050 % The format of the GetOneAuthenticPixelFromCache() method is:
2052 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2053 % const ssize_t x,const ssize_t y,Quantum *pixel,
2054 % ExceptionInfo *exception)
2056 % A description of each parameter follows:
2058 % o image: the image.
2060 % o x,y: These values define the location of the pixel to return.
2062 % o pixel: return a pixel at the specified (x,y) location.
2064 % o exception: return any errors or warnings in this structure.
2067 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2068 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2074 id = GetOpenMPThreadId();
2082 assert(image != (const Image *) NULL);
2083 assert(image->signature == MagickSignature);
2084 assert(image->cache != (Cache) NULL);
2085 cache_info=(CacheInfo *) image->cache;
2086 assert(cache_info->signature == MagickSignature);
2087 assert(id < (int) cache_info->number_threads);
2088 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2089 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2091 if (q == (Quantum *) NULL)
2093 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2094 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2095 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2096 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2097 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2098 return(MagickFalse);
2100 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2105 channel=GetPixelChannelMapChannel(image,i);
2106 pixel[channel]=q[i];
2112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2116 % G e t O n e V i r t u a l P i x e l %
2120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2122 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2123 % (x,y) location. The image background color is returned if an error occurs.
2124 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2126 % The format of the GetOneVirtualPixel() method is:
2128 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2129 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2131 % A description of each parameter follows:
2133 % o image: the image.
2135 % o x,y: These values define the location of the pixel to return.
2137 % o pixel: return a pixel at the specified (x,y) location.
2139 % o exception: return any errors or warnings in this structure.
2142 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2143 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2149 id = GetOpenMPThreadId();
2157 assert(image != (const Image *) NULL);
2158 assert(image->signature == MagickSignature);
2159 assert(image->cache != (Cache) NULL);
2160 cache_info=(CacheInfo *) image->cache;
2161 assert(cache_info->signature == MagickSignature);
2162 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2163 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2164 (GetOneVirtualPixelFromHandler) NULL)
2165 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2166 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2167 assert(id < (int) cache_info->number_threads);
2168 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2169 1UL,1UL,cache_info->nexus_info[id],exception);
2170 if (p == (const Quantum *) NULL)
2172 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2173 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2174 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2175 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2176 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2177 return(MagickFalse);
2179 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2184 channel=GetPixelChannelMapChannel(image,i);
2185 pixel[channel]=p[i];
2191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2195 + 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 %
2199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2201 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2202 % specified (x,y) location. The image background color is returned if an
2205 % The format of the GetOneVirtualPixelFromCache() method is:
2207 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2208 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2209 % Quantum *pixel,ExceptionInfo *exception)
2211 % A description of each parameter follows:
2213 % o image: the image.
2215 % o virtual_pixel_method: the virtual pixel method.
2217 % o x,y: These values define the location of the pixel to return.
2219 % o pixel: return a pixel at the specified (x,y) location.
2221 % o exception: return any errors or warnings in this structure.
2224 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2225 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2226 Quantum *pixel,ExceptionInfo *exception)
2232 id = GetOpenMPThreadId();
2240 assert(image != (const Image *) NULL);
2241 assert(image->signature == MagickSignature);
2242 assert(image->cache != (Cache) NULL);
2243 cache_info=(CacheInfo *) image->cache;
2244 assert(cache_info->signature == MagickSignature);
2245 assert(id < (int) cache_info->number_threads);
2246 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2247 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2248 cache_info->nexus_info[id],exception);
2249 if (p == (const Quantum *) NULL)
2251 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2252 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2253 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2254 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2255 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2256 return(MagickFalse);
2258 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2263 channel=GetPixelChannelMapChannel(image,i);
2264 pixel[channel]=p[i];
2270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2274 % G e t O n e V i r t u a l P i x e l I n f o %
2278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2280 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2281 % location. The image background color is returned if an error occurs. If
2282 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2284 % The format of the GetOneVirtualPixelInfo() method is:
2286 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2287 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2288 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2290 % A description of each parameter follows:
2292 % o image: the image.
2294 % o virtual_pixel_method: the virtual pixel method.
2296 % o x,y: these values define the location of the pixel to return.
2298 % o pixel: return a pixel at the specified (x,y) location.
2300 % o exception: return any errors or warnings in this structure.
2303 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2304 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2305 PixelInfo *pixel,ExceptionInfo *exception)
2311 id = GetOpenMPThreadId();
2313 register const Quantum
2316 assert(image != (const Image *) NULL);
2317 assert(image->signature == MagickSignature);
2318 assert(image->cache != (Cache) NULL);
2319 cache_info=(CacheInfo *) image->cache;
2320 assert(cache_info->signature == MagickSignature);
2321 assert(id < (int) cache_info->number_threads);
2322 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2323 cache_info->nexus_info[id],exception);
2324 GetPixelInfo(image,pixel);
2325 if (p == (const Quantum *) NULL)
2326 return(MagickFalse);
2327 GetPixelInfoPixel(image,p,pixel);
2332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2336 + G e t P i x e l C a c h e C o l o r s p a c e %
2340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2342 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2344 % The format of the GetPixelCacheColorspace() method is:
2346 % Colorspace GetPixelCacheColorspace(Cache cache)
2348 % A description of each parameter follows:
2350 % o cache: the pixel cache.
2353 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2358 assert(cache != (Cache) NULL);
2359 cache_info=(CacheInfo *) cache;
2360 assert(cache_info->signature == MagickSignature);
2361 if (cache_info->debug != MagickFalse)
2362 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2363 cache_info->filename);
2364 return(cache_info->colorspace);
2368 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2372 + G e t P i x e l C a c h e M e t h o d s %
2376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2378 % GetPixelCacheMethods() initializes the CacheMethods structure.
2380 % The format of the GetPixelCacheMethods() method is:
2382 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2384 % A description of each parameter follows:
2386 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2389 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2391 assert(cache_methods != (CacheMethods *) NULL);
2392 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2393 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2394 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2395 cache_methods->get_virtual_metacontent_from_handler=
2396 GetVirtualMetacontentFromCache;
2397 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2398 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2399 cache_methods->get_authentic_metacontent_from_handler=
2400 GetAuthenticMetacontentFromCache;
2401 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2402 cache_methods->get_one_authentic_pixel_from_handler=
2403 GetOneAuthenticPixelFromCache;
2404 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2405 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2406 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2414 + G e t P i x e l C a c h e N e x u s E x t e n t %
2418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2420 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2421 % corresponding with the last call to SetPixelCacheNexusPixels() or
2422 % GetPixelCacheNexusPixels().
2424 % The format of the GetPixelCacheNexusExtent() method is:
2426 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2427 % NexusInfo *nexus_info)
2429 % A description of each parameter follows:
2431 % o nexus_info: the nexus info.
2434 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2435 NexusInfo *nexus_info)
2443 assert(cache != NULL);
2444 cache_info=(CacheInfo *) cache;
2445 assert(cache_info->signature == MagickSignature);
2446 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2448 return((MagickSizeType) cache_info->columns*cache_info->rows);
2453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2457 + 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 %
2461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2463 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2466 % The format of the GetPixelCacheNexusMetacontent() method is:
2468 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2469 % NexusInfo *nexus_info)
2471 % A description of each parameter follows:
2473 % o cache: the pixel cache.
2475 % o nexus_info: the cache nexus to return the meta-content.
2478 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2479 NexusInfo *nexus_info)
2484 assert(cache != NULL);
2485 cache_info=(CacheInfo *) cache;
2486 assert(cache_info->signature == MagickSignature);
2487 if (cache_info->storage_class == UndefinedClass)
2488 return((void *) NULL);
2489 return(nexus_info->metacontent);
2493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2497 + G e t P i x e l C a c h e N e x u s P i x e l s %
2501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2503 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2506 % The format of the GetPixelCacheNexusPixels() method is:
2508 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2509 % NexusInfo *nexus_info)
2511 % A description of each parameter follows:
2513 % o cache: the pixel cache.
2515 % o nexus_info: the cache nexus to return the pixels.
2518 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2519 NexusInfo *nexus_info)
2524 assert(cache != NULL);
2525 cache_info=(CacheInfo *) cache;
2526 assert(cache_info->signature == MagickSignature);
2527 if (cache_info->storage_class == UndefinedClass)
2528 return((Quantum *) NULL);
2529 return(nexus_info->pixels);
2533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2537 + G e t P i x e l C a c h e P i x e l s %
2541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2543 % GetPixelCachePixels() returns the pixels associated with the specified image.
2545 % The format of the GetPixelCachePixels() method is:
2547 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2548 % ExceptionInfo *exception)
2550 % A description of each parameter follows:
2552 % o image: the image.
2554 % o length: the pixel cache length.
2556 % o exception: return any errors or warnings in this structure.
2559 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2560 ExceptionInfo *exception)
2565 assert(image != (const Image *) NULL);
2566 assert(image->signature == MagickSignature);
2567 assert(image->cache != (Cache) NULL);
2568 assert(length != (MagickSizeType *) NULL);
2569 assert(exception != (ExceptionInfo *) NULL);
2570 assert(exception->signature == MagickSignature);
2571 cache_info=(CacheInfo *) image->cache;
2572 assert(cache_info->signature == MagickSignature);
2574 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2575 return((void *) NULL);
2576 *length=cache_info->length;
2577 return((void *) cache_info->pixels);
2581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2585 + 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 %
2589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2593 % The format of the GetPixelCacheStorageClass() method is:
2595 % ClassType GetPixelCacheStorageClass(Cache cache)
2597 % A description of each parameter follows:
2599 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2601 % o cache: the pixel cache.
2604 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2609 assert(cache != (Cache) NULL);
2610 cache_info=(CacheInfo *) cache;
2611 assert(cache_info->signature == MagickSignature);
2612 if (cache_info->debug != MagickFalse)
2613 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2614 cache_info->filename);
2615 return(cache_info->storage_class);
2619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2623 + G e t P i x e l C a c h e T i l e S i z e %
2627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2629 % GetPixelCacheTileSize() returns the pixel cache tile size.
2631 % The format of the GetPixelCacheTileSize() method is:
2633 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2636 % A description of each parameter follows:
2638 % o image: the image.
2640 % o width: the optimize cache tile width in pixels.
2642 % o height: the optimize cache tile height in pixels.
2645 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2651 assert(image != (Image *) NULL);
2652 assert(image->signature == MagickSignature);
2653 if (image->debug != MagickFalse)
2654 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2655 cache_info=(CacheInfo *) image->cache;
2656 assert(cache_info->signature == MagickSignature);
2657 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2658 if (GetPixelCacheType(image) == DiskCache)
2659 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2664 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668 + G e t P i x e l C a c h e T y p e %
2672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2674 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2676 % The format of the GetPixelCacheType() method is:
2678 % CacheType GetPixelCacheType(const Image *image)
2680 % A description of each parameter follows:
2682 % o image: the image.
2685 MagickPrivate CacheType GetPixelCacheType(const Image *image)
2690 assert(image != (Image *) NULL);
2691 assert(image->signature == MagickSignature);
2692 assert(image->cache != (Cache) NULL);
2693 cache_info=(CacheInfo *) image->cache;
2694 assert(cache_info->signature == MagickSignature);
2695 return(cache_info->type);
2699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2703 + 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 %
2707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2709 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2710 % pixel cache. A virtual pixel is any pixel access that is outside the
2711 % boundaries of the image cache.
2713 % The format of the GetPixelCacheVirtualMethod() method is:
2715 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2717 % A description of each parameter follows:
2719 % o image: the image.
2722 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2727 assert(image != (Image *) NULL);
2728 assert(image->signature == MagickSignature);
2729 assert(image->cache != (Cache) NULL);
2730 cache_info=(CacheInfo *) image->cache;
2731 assert(cache_info->signature == MagickSignature);
2732 return(cache_info->virtual_pixel_method);
2736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2740 + 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 %
2744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2746 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2747 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2749 % The format of the GetVirtualMetacontentFromCache() method is:
2751 % void *GetVirtualMetacontentFromCache(const Image *image)
2753 % A description of each parameter follows:
2755 % o image: the image.
2758 static const void *GetVirtualMetacontentFromCache(const Image *image)
2764 id = GetOpenMPThreadId();
2769 assert(image != (const Image *) NULL);
2770 assert(image->signature == MagickSignature);
2771 assert(image->cache != (Cache) NULL);
2772 cache_info=(CacheInfo *) image->cache;
2773 assert(cache_info->signature == MagickSignature);
2774 assert(id < (int) cache_info->number_threads);
2775 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2776 cache_info->nexus_info[id]);
2777 return(metacontent);
2781 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2785 + 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 %
2789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2791 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2794 % The format of the GetVirtualMetacontentFromNexus() method is:
2796 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2797 % NexusInfo *nexus_info)
2799 % A description of each parameter follows:
2801 % o cache: the pixel cache.
2803 % o nexus_info: the cache nexus to return the meta-content.
2806 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2807 NexusInfo *nexus_info)
2812 assert(cache != (Cache) NULL);
2813 cache_info=(CacheInfo *) cache;
2814 assert(cache_info->signature == MagickSignature);
2815 if (cache_info->storage_class == UndefinedClass)
2816 return((void *) NULL);
2817 return(nexus_info->metacontent);
2821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2825 % G e t V i r t u a l M e t a c o n t e n t %
2829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2831 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2832 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2833 % returned if the meta-content are not available.
2835 % The format of the GetVirtualMetacontent() method is:
2837 % const void *GetVirtualMetacontent(const Image *image)
2839 % A description of each parameter follows:
2841 % o image: the image.
2844 MagickExport const void *GetVirtualMetacontent(const Image *image)
2850 id = GetOpenMPThreadId();
2855 assert(image != (const Image *) NULL);
2856 assert(image->signature == MagickSignature);
2857 assert(image->cache != (Cache) NULL);
2858 cache_info=(CacheInfo *) image->cache;
2859 assert(cache_info->signature == MagickSignature);
2860 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2861 (GetVirtualMetacontentFromHandler) NULL)
2863 metacontent=cache_info->methods.
2864 get_virtual_metacontent_from_handler(image);
2865 return(metacontent);
2867 assert(id < (int) cache_info->number_threads);
2868 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2869 cache_info->nexus_info[id]);
2870 return(metacontent);
2874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2878 + G e t V i r t u a l P i x e l s F r o m N e x u s %
2882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2885 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2886 % is returned if the pixels are transferred, otherwise a NULL is returned.
2888 % The format of the GetVirtualPixelsFromNexus() method is:
2890 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2891 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2892 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2893 % ExceptionInfo *exception)
2895 % A description of each parameter follows:
2897 % o image: the image.
2899 % o virtual_pixel_method: the virtual pixel method.
2901 % o x,y,columns,rows: These values define the perimeter of a region of
2904 % o nexus_info: the cache nexus to acquire.
2906 % o exception: return any errors or warnings in this structure.
2913 0, 48, 12, 60, 3, 51, 15, 63,
2914 32, 16, 44, 28, 35, 19, 47, 31,
2915 8, 56, 4, 52, 11, 59, 7, 55,
2916 40, 24, 36, 20, 43, 27, 39, 23,
2917 2, 50, 14, 62, 1, 49, 13, 61,
2918 34, 18, 46, 30, 33, 17, 45, 29,
2919 10, 58, 6, 54, 9, 57, 5, 53,
2920 42, 26, 38, 22, 41, 25, 37, 21
2923 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2928 index=x+DitherMatrix[x & 0x07]-32L;
2931 if (index >= (ssize_t) columns)
2932 return((ssize_t) columns-1L);
2936 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2941 index=y+DitherMatrix[y & 0x07]-32L;
2944 if (index >= (ssize_t) rows)
2945 return((ssize_t) rows-1L);
2949 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2953 if (x >= (ssize_t) columns)
2954 return((ssize_t) (columns-1));
2958 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2962 if (y >= (ssize_t) rows)
2963 return((ssize_t) (rows-1));
2967 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2969 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2972 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2974 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2977 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2978 const size_t extent)
2984 Compute the remainder of dividing offset by extent. It returns not only
2985 the quotient (tile the offset falls in) but also the positive remainer
2986 within that tile such that 0 <= remainder < extent. This method is
2987 essentially a ldiv() using a floored modulo division rather than the
2988 normal default truncated modulo division.
2990 modulo.quotient=offset/(ssize_t) extent;
2993 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2997 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2998 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2999 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3000 ExceptionInfo *exception)
3017 virtual_pixel[CompositePixelChannel];
3022 register const Quantum
3035 register unsigned char
3042 *virtual_metacontent;
3047 assert(image != (const Image *) NULL);
3048 assert(image->signature == MagickSignature);
3049 assert(image->cache != (Cache) NULL);
3050 cache_info=(CacheInfo *) image->cache;
3051 assert(cache_info->signature == MagickSignature);
3052 if (cache_info->type == UndefinedCache)
3053 return((const Quantum *) NULL);
3056 region.width=columns;
3058 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3059 if (pixels == (Quantum *) NULL)
3060 return((const Quantum *) NULL);
3062 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3063 nexus_info->region.x;
3064 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3065 nexus_info->region.width-1L;
3066 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3067 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3068 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3069 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3075 Pixel request is inside cache extents.
3077 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3079 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3080 if (status == MagickFalse)
3081 return((const Quantum *) NULL);
3082 if (cache_info->metacontent_extent != 0)
3084 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3085 if (status == MagickFalse)
3086 return((const Quantum *) NULL);
3091 Pixel request is outside cache extents.
3093 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3094 virtual_nexus=AcquirePixelCacheNexus(1);
3095 if (virtual_nexus == (NexusInfo **) NULL)
3097 if (virtual_nexus != (NexusInfo **) NULL)
3098 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3099 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3100 "UnableToGetCacheNexus","`%s'",image->filename);
3101 return((const Quantum *) NULL);
3103 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3104 sizeof(*virtual_pixel));
3105 virtual_metacontent=(void *) NULL;
3106 switch (virtual_pixel_method)
3108 case BackgroundVirtualPixelMethod:
3109 case BlackVirtualPixelMethod:
3110 case GrayVirtualPixelMethod:
3111 case TransparentVirtualPixelMethod:
3112 case MaskVirtualPixelMethod:
3113 case WhiteVirtualPixelMethod:
3114 case EdgeVirtualPixelMethod:
3115 case CheckerTileVirtualPixelMethod:
3116 case HorizontalTileVirtualPixelMethod:
3117 case VerticalTileVirtualPixelMethod:
3119 if (cache_info->metacontent_extent != 0)
3122 Acquire a metacontent buffer.
3124 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3125 cache_info->metacontent_extent);
3126 if (virtual_metacontent == (void *) NULL)
3128 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3129 (void) ThrowMagickException(exception,GetMagickModule(),
3130 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3131 return((const Quantum *) NULL);
3133 (void) ResetMagickMemory(virtual_metacontent,0,
3134 cache_info->metacontent_extent);
3136 switch (virtual_pixel_method)
3138 case BlackVirtualPixelMethod:
3140 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3141 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3142 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3145 case GrayVirtualPixelMethod:
3147 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3148 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3150 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3153 case TransparentVirtualPixelMethod:
3155 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3156 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3157 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3160 case MaskVirtualPixelMethod:
3161 case WhiteVirtualPixelMethod:
3163 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3164 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3165 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3170 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3172 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3174 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3176 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3178 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3188 for (v=0; v < (ssize_t) rows; v++)
3190 for (u=0; u < (ssize_t) columns; u+=length)
3192 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3193 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3194 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3202 Transfer a single pixel.
3204 length=(MagickSizeType) 1;
3205 switch (virtual_pixel_method)
3209 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3210 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3211 1UL,1UL,*virtual_nexus,exception);
3212 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3215 case RandomVirtualPixelMethod:
3217 if (cache_info->random_info == (RandomInfo *) NULL)
3218 cache_info->random_info=AcquireRandomInfo();
3219 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3220 RandomX(cache_info->random_info,cache_info->columns),
3221 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3222 *virtual_nexus,exception);
3223 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3226 case DitherVirtualPixelMethod:
3228 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3229 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3230 1UL,1UL,*virtual_nexus,exception);
3231 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3234 case TileVirtualPixelMethod:
3236 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3237 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3238 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3239 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3241 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3244 case MirrorVirtualPixelMethod:
3246 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3247 if ((x_modulo.quotient & 0x01) == 1L)
3248 x_modulo.remainder=(ssize_t) cache_info->columns-
3249 x_modulo.remainder-1L;
3250 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3251 if ((y_modulo.quotient & 0x01) == 1L)
3252 y_modulo.remainder=(ssize_t) cache_info->rows-
3253 y_modulo.remainder-1L;
3254 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3255 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3257 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3260 case HorizontalTileEdgeVirtualPixelMethod:
3262 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3263 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3264 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3265 *virtual_nexus,exception);
3266 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3269 case VerticalTileEdgeVirtualPixelMethod:
3271 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3272 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3273 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3274 *virtual_nexus,exception);
3275 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3278 case BackgroundVirtualPixelMethod:
3279 case BlackVirtualPixelMethod:
3280 case GrayVirtualPixelMethod:
3281 case TransparentVirtualPixelMethod:
3282 case MaskVirtualPixelMethod:
3283 case WhiteVirtualPixelMethod:
3286 r=virtual_metacontent;
3289 case EdgeVirtualPixelMethod:
3290 case CheckerTileVirtualPixelMethod:
3292 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3293 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3294 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3297 r=virtual_metacontent;
3300 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3301 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3303 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3306 case HorizontalTileVirtualPixelMethod:
3308 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3311 r=virtual_metacontent;
3314 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3315 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3316 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3317 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3319 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3322 case VerticalTileVirtualPixelMethod:
3324 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3327 r=virtual_metacontent;
3330 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3331 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3332 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3333 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3335 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3339 if (p == (const Quantum *) NULL)
3341 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3343 q+=cache_info->number_channels;
3344 if ((s != (void *) NULL) && (r != (const void *) NULL))
3346 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3347 s+=cache_info->metacontent_extent;
3352 Transfer a run of pixels.
3354 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3355 length,1UL,*virtual_nexus,exception);
3356 if (p == (const Quantum *) NULL)
3358 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3359 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3360 q+=length*cache_info->number_channels;
3361 if ((r != (void *) NULL) && (s != (const void *) NULL))
3363 (void) memcpy(s,r,(size_t) length);
3364 s+=length*cache_info->metacontent_extent;
3371 if (virtual_metacontent != (void *) NULL)
3372 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3373 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3382 + G e t V i r t u a l P i x e l C a c h e %
3386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3388 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3389 % cache as defined by the geometry parameters. A pointer to the pixels
3390 % is returned if the pixels are transferred, otherwise a NULL is returned.
3392 % The format of the GetVirtualPixelCache() method is:
3394 % const Quantum *GetVirtualPixelCache(const Image *image,
3395 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3396 % const ssize_t y,const size_t columns,const size_t rows,
3397 % ExceptionInfo *exception)
3399 % A description of each parameter follows:
3401 % o image: the image.
3403 % o virtual_pixel_method: the virtual pixel method.
3405 % o x,y,columns,rows: These values define the perimeter of a region of
3408 % o exception: return any errors or warnings in this structure.
3411 static const Quantum *GetVirtualPixelCache(const Image *image,
3412 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3413 const size_t columns,const size_t rows,ExceptionInfo *exception)
3419 id = GetOpenMPThreadId();
3424 assert(image != (const Image *) NULL);
3425 assert(image->signature == MagickSignature);
3426 assert(image->cache != (Cache) NULL);
3427 cache_info=(CacheInfo *) image->cache;
3428 assert(cache_info->signature == MagickSignature);
3429 assert(id < (int) cache_info->number_threads);
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3431 cache_info->nexus_info[id],exception);
3436 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3440 % G e t V i r t u a l P i x e l Q u e u e %
3444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3446 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3447 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3449 % The format of the GetVirtualPixelQueue() method is:
3451 % const Quantum *GetVirtualPixelQueue(const Image image)
3453 % A description of each parameter follows:
3455 % o image: the image.
3458 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3464 id = GetOpenMPThreadId();
3466 assert(image != (const Image *) NULL);
3467 assert(image->signature == MagickSignature);
3468 assert(image->cache != (Cache) NULL);
3469 cache_info=(CacheInfo *) image->cache;
3470 assert(cache_info->signature == MagickSignature);
3471 if (cache_info->methods.get_virtual_pixels_handler !=
3472 (GetVirtualPixelsHandler) NULL)
3473 return(cache_info->methods.get_virtual_pixels_handler(image));
3474 assert(id < (int) cache_info->number_threads);
3475 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3483 % G e t V i r t u a l P i x e l s %
3487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3489 % GetVirtualPixels() returns an immutable pixel region. If the
3490 % region is successfully accessed, a pointer to it is returned, otherwise
3491 % NULL is returned. The returned pointer may point to a temporary working
3492 % copy of the pixels or it may point to the original pixels in memory.
3493 % Performance is maximized if the selected region is part of one row, or one
3494 % or more full rows, since there is opportunity to access the pixels in-place
3495 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3496 % returned pointer must *never* be deallocated by the user.
3498 % Pixels accessed via the returned pointer represent a simple array of type
3499 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3500 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3501 % access the meta-content (of type void) corresponding to the the
3504 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3506 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3507 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3508 % GetCacheViewAuthenticPixels() instead.
3510 % The format of the GetVirtualPixels() method is:
3512 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3513 % const ssize_t y,const size_t columns,const size_t rows,
3514 % ExceptionInfo *exception)
3516 % A description of each parameter follows:
3518 % o image: the image.
3520 % o x,y,columns,rows: These values define the perimeter of a region of
3523 % o exception: return any errors or warnings in this structure.
3526 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3527 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3528 ExceptionInfo *exception)
3534 id = GetOpenMPThreadId();
3539 assert(image != (const Image *) NULL);
3540 assert(image->signature == MagickSignature);
3541 assert(image->cache != (Cache) NULL);
3542 cache_info=(CacheInfo *) image->cache;
3543 assert(cache_info->signature == MagickSignature);
3544 if (cache_info->methods.get_virtual_pixel_handler !=
3545 (GetVirtualPixelHandler) NULL)
3546 return(cache_info->methods.get_virtual_pixel_handler(image,
3547 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3548 assert(id < (int) cache_info->number_threads);
3549 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3550 columns,rows,cache_info->nexus_info[id],exception);
3555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3559 + G e t V i r t u a l P i x e l s F r o m C a c h e %
3563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3565 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3566 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3568 % The format of the GetVirtualPixelsCache() method is:
3570 % Quantum *GetVirtualPixelsCache(const Image *image)
3572 % A description of each parameter follows:
3574 % o image: the image.
3577 static const Quantum *GetVirtualPixelsCache(const Image *image)
3583 id = GetOpenMPThreadId();
3585 assert(image != (const Image *) NULL);
3586 assert(image->signature == MagickSignature);
3587 assert(image->cache != (Cache) NULL);
3588 cache_info=(CacheInfo *) image->cache;
3589 assert(cache_info->signature == MagickSignature);
3590 assert(id < (int) cache_info->number_threads);
3591 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3599 + G e t V i r t u a l P i x e l s N e x u s %
3603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3605 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3608 % The format of the GetVirtualPixelsNexus() method is:
3610 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3611 % NexusInfo *nexus_info)
3613 % A description of each parameter follows:
3615 % o cache: the pixel cache.
3617 % o nexus_info: the cache nexus to return the colormap pixels.
3620 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3621 NexusInfo *nexus_info)
3626 assert(cache != (Cache) NULL);
3627 cache_info=(CacheInfo *) cache;
3628 assert(cache_info->signature == MagickSignature);
3629 if (cache_info->storage_class == UndefinedClass)
3630 return((Quantum *) NULL);
3631 return((const Quantum *) nexus_info->pixels);
3635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3639 + O p e n P i x e l C a c h e %
3643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3645 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3646 % dimensions, allocating space for the image pixels and optionally the
3647 % metacontent, and memory mapping the cache if it is disk based. The cache
3648 % nexus array is initialized as well.
3650 % The format of the OpenPixelCache() method is:
3652 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3653 % ExceptionInfo *exception)
3655 % A description of each parameter follows:
3657 % o image: the image.
3659 % o mode: ReadMode, WriteMode, or IOMode.
3661 % o exception: return any errors or warnings in this structure.
3665 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3667 cache_info->mapped=MagickFalse;
3668 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3669 cache_info->length);
3670 if (cache_info->pixels == (Quantum *) NULL)
3672 cache_info->mapped=MagickTrue;
3673 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3674 cache_info->length);
3678 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3688 cache_info=(CacheInfo *) image->cache;
3689 if (image->debug != MagickFalse)
3692 format[MaxTextExtent],
3693 message[MaxTextExtent];
3695 (void) FormatMagickSize(length,MagickFalse,format);
3696 (void) FormatLocaleString(message,MaxTextExtent,
3697 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3698 cache_info->cache_filename,cache_info->file,format);
3699 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3701 if (length != (MagickSizeType) ((MagickOffsetType) length))
3702 return(MagickFalse);
3703 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3705 return(MagickFalse);
3706 if ((MagickSizeType) extent >= length)
3708 offset=(MagickOffsetType) length-1;
3709 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3710 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3713 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3714 ExceptionInfo *exception)
3721 format[MaxTextExtent],
3722 message[MaxTextExtent];
3739 assert(image != (const Image *) NULL);
3740 assert(image->signature == MagickSignature);
3741 assert(image->cache != (Cache) NULL);
3742 if (image->debug != MagickFalse)
3743 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3744 if ((image->columns == 0) || (image->rows == 0))
3745 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3746 cache_info=(CacheInfo *) image->cache;
3747 assert(cache_info->signature == MagickSignature);
3748 source_info=(*cache_info);
3749 source_info.file=(-1);
3750 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3751 image->filename,(double) GetImageIndexInList(image));
3752 cache_info->storage_class=image->storage_class;
3753 cache_info->colorspace=image->colorspace;
3754 cache_info->matte=image->matte;
3755 cache_info->mask=image->mask;
3756 cache_info->rows=image->rows;
3757 cache_info->columns=image->columns;
3758 InitializePixelChannelMap(image);
3759 cache_info->number_channels=GetPixelChannels(image);
3760 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3761 sizeof(*image->channel_map));
3762 cache_info->metacontent_extent=image->metacontent_extent;
3763 cache_info->mode=mode;
3764 if (image->ping != MagickFalse)
3766 cache_info->type=PingCache;
3767 cache_info->pixels=(Quantum *) NULL;
3768 cache_info->metacontent=(void *) NULL;
3769 cache_info->length=0;
3772 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3773 packet_size=cache_info->number_channels*sizeof(Quantum);
3774 if (image->metacontent_extent != 0)
3775 packet_size+=cache_info->metacontent_extent;
3776 length=number_pixels*packet_size;
3777 columns=(size_t) (length/cache_info->rows/packet_size);
3778 if (cache_info->columns != columns)
3779 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3781 cache_info->length=length;
3782 p=cache_info->channel_map;
3783 q=source_info.channel_map;
3784 if ((cache_info->type != UndefinedCache) &&
3785 (cache_info->columns <= source_info.columns) &&
3786 (cache_info->rows <= source_info.rows) &&
3787 (cache_info->number_channels <= source_info.number_channels) &&
3788 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
3789 (cache_info->metacontent_extent <= source_info.metacontent_extent))
3792 Inline pixel cache clone optimization.
3794 if ((cache_info->columns == source_info.columns) &&
3795 (cache_info->rows == source_info.rows) &&
3796 (cache_info->number_channels == source_info.number_channels) &&
3797 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
3798 (cache_info->metacontent_extent == source_info.metacontent_extent))
3800 return(ClonePixelCachePixels(cache_info,&source_info,exception));
3802 status=AcquireMagickResource(AreaResource,cache_info->length);
3803 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3804 cache_info->metacontent_extent);
3805 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3807 status=AcquireMagickResource(MemoryResource,cache_info->length);
3808 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3809 (cache_info->type == MemoryCache))
3811 AllocatePixelCachePixels(cache_info);
3812 if (cache_info->pixels == (Quantum *) NULL)
3813 cache_info->pixels=source_info.pixels;
3817 Create memory pixel cache.
3820 if (image->debug != MagickFalse)
3822 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3823 (void) FormatLocaleString(message,MaxTextExtent,
3824 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3825 cache_info->filename,cache_info->mapped != MagickFalse ?
3826 "anonymous" : "heap",(double) cache_info->columns,(double)
3827 cache_info->rows,(double) cache_info->number_channels,
3829 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3832 cache_info->type=MemoryCache;
3833 cache_info->metacontent=(void *) NULL;
3834 if (cache_info->metacontent_extent != 0)
3835 cache_info->metacontent=(void *) (cache_info->pixels+
3836 number_pixels*cache_info->number_channels);
3837 if ((source_info.storage_class != UndefinedClass) &&
3840 status=ClonePixelCachePixels(cache_info,&source_info,
3842 RelinquishPixelCachePixels(&source_info);
3847 RelinquishMagickResource(MemoryResource,cache_info->length);
3850 Create pixel cache on disk.
3852 status=AcquireMagickResource(DiskResource,cache_info->length);
3853 if (status == MagickFalse)
3855 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3856 "CacheResourcesExhausted","`%s'",image->filename);
3857 return(MagickFalse);
3859 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3861 (void) ClosePixelCacheOnDisk(cache_info);
3862 *cache_info->cache_filename='\0';
3864 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3866 RelinquishMagickResource(DiskResource,cache_info->length);
3867 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3869 return(MagickFalse);
3871 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3872 cache_info->length);
3873 if (status == MagickFalse)
3875 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3877 return(MagickFalse);
3879 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3880 cache_info->metacontent_extent);
3881 if (length != (MagickSizeType) ((size_t) length))
3882 cache_info->type=DiskCache;
3885 status=AcquireMagickResource(MapResource,cache_info->length);
3886 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3887 (cache_info->type != MemoryCache))
3888 cache_info->type=DiskCache;
3891 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3892 cache_info->offset,(size_t) cache_info->length);
3893 if (cache_info->pixels == (Quantum *) NULL)
3895 cache_info->type=DiskCache;
3896 cache_info->pixels=source_info.pixels;
3901 Create file-backed memory-mapped pixel cache.
3904 (void) ClosePixelCacheOnDisk(cache_info);
3905 cache_info->type=MapCache;
3906 cache_info->mapped=MagickTrue;
3907 cache_info->metacontent=(void *) NULL;
3908 if (cache_info->metacontent_extent != 0)
3909 cache_info->metacontent=(void *) (cache_info->pixels+
3910 number_pixels*cache_info->number_channels);
3911 if ((source_info.storage_class != UndefinedClass) &&
3914 status=ClonePixelCachePixels(cache_info,&source_info,
3916 RelinquishPixelCachePixels(&source_info);
3918 if (image->debug != MagickFalse)
3920 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3921 (void) FormatLocaleString(message,MaxTextExtent,
3922 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
3923 cache_info->filename,cache_info->cache_filename,
3924 cache_info->file,(double) cache_info->columns,(double)
3925 cache_info->rows,(double) cache_info->number_channels,
3927 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3933 RelinquishMagickResource(MapResource,cache_info->length);
3936 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3938 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3939 RelinquishPixelCachePixels(&source_info);
3941 if (image->debug != MagickFalse)
3943 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3944 (void) FormatLocaleString(message,MaxTextExtent,
3945 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
3946 cache_info->cache_filename,cache_info->file,(double)
3947 cache_info->columns,(double) cache_info->rows,(double)
3948 cache_info->number_channels,format);
3949 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3959 + P e r s i s t P i x e l C a c h e %
3963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3965 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3966 % persistent pixel cache is one that resides on disk and is not destroyed
3967 % when the program exits.
3969 % The format of the PersistPixelCache() method is:
3971 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3972 % const MagickBooleanType attach,MagickOffsetType *offset,
3973 % ExceptionInfo *exception)
3975 % A description of each parameter follows:
3977 % o image: the image.
3979 % o filename: the persistent pixel cache filename.
3981 % o attach: A value other than zero initializes the persistent pixel cache.
3983 % o initialize: A value other than zero initializes the persistent pixel
3986 % o offset: the offset in the persistent cache to store pixels.
3988 % o exception: return any errors or warnings in this structure.
3991 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3992 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3993 ExceptionInfo *exception)
4008 assert(image != (Image *) NULL);
4009 assert(image->signature == MagickSignature);
4010 if (image->debug != MagickFalse)
4011 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4012 assert(image->cache != (void *) NULL);
4013 assert(filename != (const char *) NULL);
4014 assert(offset != (MagickOffsetType *) NULL);
4015 page_size=GetMagickPageSize();
4016 cache_info=(CacheInfo *) image->cache;
4017 assert(cache_info->signature == MagickSignature);
4018 if (attach != MagickFalse)
4021 Attach existing persistent pixel cache.
4023 if (image->debug != MagickFalse)
4024 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4025 "attach persistent cache");
4026 (void) CopyMagickString(cache_info->cache_filename,filename,
4028 cache_info->type=DiskCache;
4029 cache_info->offset=(*offset);
4030 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4031 return(MagickFalse);
4032 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4035 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4036 (cache_info->reference_count == 1))
4038 LockSemaphoreInfo(cache_info->semaphore);
4039 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4040 (cache_info->reference_count == 1))
4046 Usurp existing persistent pixel cache.
4048 status=rename_utf8(cache_info->cache_filename,filename);
4051 (void) CopyMagickString(cache_info->cache_filename,filename,
4053 *offset+=cache_info->length+page_size-(cache_info->length %
4055 UnlockSemaphoreInfo(cache_info->semaphore);
4056 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4057 if (image->debug != MagickFalse)
4058 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4059 "Usurp resident persistent cache");
4063 UnlockSemaphoreInfo(cache_info->semaphore);
4066 Clone persistent pixel cache.
4068 clone_image=(*image);
4069 clone_info=(CacheInfo *) clone_image.cache;
4070 image->cache=ClonePixelCache(cache_info);
4071 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4072 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4073 cache_info->type=DiskCache;
4074 cache_info->offset=(*offset);
4075 cache_info=(CacheInfo *) image->cache;
4076 status=OpenPixelCache(image,IOMode,exception);
4077 if (status != MagickFalse)
4078 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4079 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4080 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4089 + 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 %
4093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4095 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4096 % defined by the region rectangle and returns a pointer to the region. This
4097 % region is subsequently transferred from the pixel cache with
4098 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4099 % pixels are transferred, otherwise a NULL is returned.
4101 % The format of the QueueAuthenticPixelCacheNexus() method is:
4103 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4104 % const ssize_t y,const size_t columns,const size_t rows,
4105 % const MagickBooleanType clone,NexusInfo *nexus_info,
4106 % ExceptionInfo *exception)
4108 % A description of each parameter follows:
4110 % o image: the image.
4112 % o x,y,columns,rows: These values define the perimeter of a region of
4115 % o nexus_info: the cache nexus to set.
4117 % o clone: clone the pixel cache.
4119 % o exception: return any errors or warnings in this structure.
4122 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4123 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4124 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4139 Validate pixel cache geometry.
4141 assert(image != (const Image *) NULL);
4142 assert(image->signature == MagickSignature);
4143 assert(image->cache != (Cache) NULL);
4144 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4145 if (cache_info == (Cache) NULL)
4146 return((Quantum *) NULL);
4147 assert(cache_info->signature == MagickSignature);
4148 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4151 "NoPixelsDefinedInCache","`%s'",image->filename);
4152 return((Quantum *) NULL);
4154 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4155 (y >= (ssize_t) cache_info->rows))
4157 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4158 "PixelsAreNotAuthentic","`%s'",image->filename);
4159 return((Quantum *) NULL);
4161 offset=(MagickOffsetType) y*cache_info->columns+x;
4163 return((Quantum *) NULL);
4164 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4165 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4166 if ((MagickSizeType) offset >= number_pixels)
4167 return((Quantum *) NULL);
4173 region.width=columns;
4175 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4183 + 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 %
4187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4189 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4190 % defined by the region rectangle and returns a pointer to the region. This
4191 % region is subsequently transferred from the pixel cache with
4192 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4193 % pixels are transferred, otherwise a NULL is returned.
4195 % The format of the QueueAuthenticPixelsCache() method is:
4197 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4198 % const ssize_t y,const size_t columns,const size_t rows,
4199 % ExceptionInfo *exception)
4201 % A description of each parameter follows:
4203 % o image: the image.
4205 % o x,y,columns,rows: These values define the perimeter of a region of
4208 % o exception: return any errors or warnings in this structure.
4211 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4212 const ssize_t y,const size_t columns,const size_t rows,
4213 ExceptionInfo *exception)
4219 id = GetOpenMPThreadId();
4224 assert(image != (const Image *) NULL);
4225 assert(image->signature == MagickSignature);
4226 assert(image->cache != (Cache) NULL);
4227 cache_info=(CacheInfo *) image->cache;
4228 assert(cache_info->signature == MagickSignature);
4229 assert(id < (int) cache_info->number_threads);
4230 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4231 cache_info->nexus_info[id],exception);
4236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4240 % Q u e u e A u t h e n t i c P i x e l s %
4244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4246 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4247 % successfully initialized a pointer to a Quantum array representing the
4248 % region is returned, otherwise NULL is returned. The returned pointer may
4249 % point to a temporary working buffer for the pixels or it may point to the
4250 % final location of the pixels in memory.
4252 % Write-only access means that any existing pixel values corresponding to
4253 % the region are ignored. This is useful if the initial image is being
4254 % created from scratch, or if the existing pixel values are to be
4255 % completely replaced without need to refer to their pre-existing values.
4256 % The application is free to read and write the pixel buffer returned by
4257 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4258 % initialize the pixel array values. Initializing pixel array values is the
4259 % application's responsibility.
4261 % Performance is maximized if the selected region is part of one row, or
4262 % one or more full rows, since then there is opportunity to access the
4263 % pixels in-place (without a copy) if the image is in memory, or in a
4264 % memory-mapped file. The returned pointer must *never* be deallocated
4267 % Pixels accessed via the returned pointer represent a simple array of type
4268 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4269 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4270 % obtain the meta-content (of type void) corresponding to the region.
4271 % Once the Quantum (and/or Quantum) array has been updated, the
4272 % changes must be saved back to the underlying image using
4273 % SyncAuthenticPixels() or they may be lost.
4275 % The format of the QueueAuthenticPixels() method is:
4277 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4278 % const ssize_t y,const size_t columns,const size_t rows,
4279 % ExceptionInfo *exception)
4281 % A description of each parameter follows:
4283 % o image: the image.
4285 % o x,y,columns,rows: These values define the perimeter of a region of
4288 % o exception: return any errors or warnings in this structure.
4291 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4292 const ssize_t y,const size_t columns,const size_t rows,
4293 ExceptionInfo *exception)
4299 id = GetOpenMPThreadId();
4304 assert(image != (Image *) NULL);
4305 assert(image->signature == MagickSignature);
4306 assert(image->cache != (Cache) NULL);
4307 cache_info=(CacheInfo *) image->cache;
4308 assert(cache_info->signature == MagickSignature);
4309 if (cache_info->methods.queue_authentic_pixels_handler !=
4310 (QueueAuthenticPixelsHandler) NULL)
4312 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4313 columns,rows,exception);
4316 assert(id < (int) cache_info->number_threads);
4317 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4318 cache_info->nexus_info[id],exception);
4323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4327 + 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 %
4331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4333 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4336 % The format of the ReadPixelCacheMetacontent() method is:
4338 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4339 % NexusInfo *nexus_info,ExceptionInfo *exception)
4341 % A description of each parameter follows:
4343 % o cache_info: the pixel cache.
4345 % o nexus_info: the cache nexus to read the metacontent.
4347 % o exception: return any errors or warnings in this structure.
4350 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4351 NexusInfo *nexus_info,ExceptionInfo *exception)
4364 register unsigned char
4370 if (cache_info->metacontent_extent == 0)
4371 return(MagickFalse);
4372 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4374 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4375 nexus_info->region.x;
4376 length=(MagickSizeType) nexus_info->region.width*
4377 cache_info->metacontent_extent;
4378 rows=nexus_info->region.height;
4380 q=(unsigned char *) nexus_info->metacontent;
4381 switch (cache_info->type)
4386 register unsigned char
4390 Read meta-content from memory.
4392 if ((cache_info->columns == nexus_info->region.width) &&
4393 (extent == (MagickSizeType) ((size_t) extent)))
4398 p=(unsigned char *) cache_info->metacontent+offset*
4399 cache_info->metacontent_extent;
4400 for (y=0; y < (ssize_t) rows; y++)
4402 (void) memcpy(q,p,(size_t) length);
4403 p+=cache_info->metacontent_extent*cache_info->columns;
4404 q+=cache_info->metacontent_extent*nexus_info->region.width;
4411 Read meta content from disk.
4413 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4415 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4416 cache_info->cache_filename);
4417 return(MagickFalse);
4419 if ((cache_info->columns == nexus_info->region.width) &&
4420 (extent <= MagickMaxBufferExtent))
4425 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4426 for (y=0; y < (ssize_t) rows; y++)
4428 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4429 cache_info->number_channels*sizeof(Quantum)+offset*
4430 cache_info->metacontent_extent,length,(unsigned char *) q);
4431 if ((MagickSizeType) count != length)
4433 offset+=cache_info->columns;
4434 q+=cache_info->metacontent_extent*nexus_info->region.width;
4436 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4437 (void) ClosePixelCacheOnDisk(cache_info);
4438 if (y < (ssize_t) rows)
4440 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4441 cache_info->cache_filename);
4442 return(MagickFalse);
4449 if ((cache_info->debug != MagickFalse) &&
4450 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4451 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4452 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4453 nexus_info->region.width,(double) nexus_info->region.height,(double)
4454 nexus_info->region.x,(double) nexus_info->region.y);
4459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4463 + R e a d P i x e l C a c h e P i x e l s %
4467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4469 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4472 % The format of the ReadPixelCachePixels() method is:
4474 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4475 % NexusInfo *nexus_info,ExceptionInfo *exception)
4477 % A description of each parameter follows:
4479 % o cache_info: the pixel cache.
4481 % o nexus_info: the cache nexus to read the pixels.
4483 % o exception: return any errors or warnings in this structure.
4486 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4487 NexusInfo *nexus_info,ExceptionInfo *exception)
4506 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4508 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4509 nexus_info->region.x;
4510 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4512 rows=nexus_info->region.height;
4514 q=nexus_info->pixels;
4515 switch (cache_info->type)
4524 Read pixels from memory.
4526 if ((cache_info->columns == nexus_info->region.width) &&
4527 (extent == (MagickSizeType) ((size_t) extent)))
4532 p=cache_info->pixels+offset*cache_info->number_channels;
4533 for (y=0; y < (ssize_t) rows; y++)
4535 (void) memcpy(q,p,(size_t) length);
4536 p+=cache_info->number_channels*cache_info->columns;
4537 q+=cache_info->number_channels*nexus_info->region.width;
4544 Read pixels from disk.
4546 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4548 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4549 cache_info->cache_filename);
4550 return(MagickFalse);
4552 if ((cache_info->columns == nexus_info->region.width) &&
4553 (extent <= MagickMaxBufferExtent))
4558 for (y=0; y < (ssize_t) rows; y++)
4560 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4561 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4562 if ((MagickSizeType) count != length)
4564 offset+=cache_info->columns;
4565 q+=cache_info->number_channels*nexus_info->region.width;
4567 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4568 (void) ClosePixelCacheOnDisk(cache_info);
4569 if (y < (ssize_t) rows)
4571 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4572 cache_info->cache_filename);
4573 return(MagickFalse);
4580 if ((cache_info->debug != MagickFalse) &&
4581 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4582 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4583 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4584 nexus_info->region.width,(double) nexus_info->region.height,(double)
4585 nexus_info->region.x,(double) nexus_info->region.y);
4590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4594 + R e f e r e n c e P i x e l C a c h e %
4598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4600 % ReferencePixelCache() increments the reference count associated with the
4601 % pixel cache returning a pointer to the cache.
4603 % The format of the ReferencePixelCache method is:
4605 % Cache ReferencePixelCache(Cache cache_info)
4607 % A description of each parameter follows:
4609 % o cache_info: the pixel cache.
4612 MagickPrivate Cache ReferencePixelCache(Cache cache)
4617 assert(cache != (Cache *) NULL);
4618 cache_info=(CacheInfo *) cache;
4619 assert(cache_info->signature == MagickSignature);
4620 LockSemaphoreInfo(cache_info->semaphore);
4621 cache_info->reference_count++;
4622 UnlockSemaphoreInfo(cache_info->semaphore);
4627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4631 + S e t P i x e l C a c h e M e t h o d s %
4635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4637 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4639 % The format of the SetPixelCacheMethods() method is:
4641 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4643 % A description of each parameter follows:
4645 % o cache: the pixel cache.
4647 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4650 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4655 GetOneAuthenticPixelFromHandler
4656 get_one_authentic_pixel_from_handler;
4658 GetOneVirtualPixelFromHandler
4659 get_one_virtual_pixel_from_handler;
4662 Set cache pixel methods.
4664 assert(cache != (Cache) NULL);
4665 assert(cache_methods != (CacheMethods *) NULL);
4666 cache_info=(CacheInfo *) cache;
4667 assert(cache_info->signature == MagickSignature);
4668 if (cache_info->debug != MagickFalse)
4669 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4670 cache_info->filename);
4671 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4672 cache_info->methods.get_virtual_pixel_handler=
4673 cache_methods->get_virtual_pixel_handler;
4674 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4675 cache_info->methods.destroy_pixel_handler=
4676 cache_methods->destroy_pixel_handler;
4677 if (cache_methods->get_virtual_metacontent_from_handler !=
4678 (GetVirtualMetacontentFromHandler) NULL)
4679 cache_info->methods.get_virtual_metacontent_from_handler=
4680 cache_methods->get_virtual_metacontent_from_handler;
4681 if (cache_methods->get_authentic_pixels_handler !=
4682 (GetAuthenticPixelsHandler) NULL)
4683 cache_info->methods.get_authentic_pixels_handler=
4684 cache_methods->get_authentic_pixels_handler;
4685 if (cache_methods->queue_authentic_pixels_handler !=
4686 (QueueAuthenticPixelsHandler) NULL)
4687 cache_info->methods.queue_authentic_pixels_handler=
4688 cache_methods->queue_authentic_pixels_handler;
4689 if (cache_methods->sync_authentic_pixels_handler !=
4690 (SyncAuthenticPixelsHandler) NULL)
4691 cache_info->methods.sync_authentic_pixels_handler=
4692 cache_methods->sync_authentic_pixels_handler;
4693 if (cache_methods->get_authentic_pixels_from_handler !=
4694 (GetAuthenticPixelsFromHandler) NULL)
4695 cache_info->methods.get_authentic_pixels_from_handler=
4696 cache_methods->get_authentic_pixels_from_handler;
4697 if (cache_methods->get_authentic_metacontent_from_handler !=
4698 (GetAuthenticMetacontentFromHandler) NULL)
4699 cache_info->methods.get_authentic_metacontent_from_handler=
4700 cache_methods->get_authentic_metacontent_from_handler;
4701 get_one_virtual_pixel_from_handler=
4702 cache_info->methods.get_one_virtual_pixel_from_handler;
4703 if (get_one_virtual_pixel_from_handler !=
4704 (GetOneVirtualPixelFromHandler) NULL)
4705 cache_info->methods.get_one_virtual_pixel_from_handler=
4706 cache_methods->get_one_virtual_pixel_from_handler;
4707 get_one_authentic_pixel_from_handler=
4708 cache_methods->get_one_authentic_pixel_from_handler;
4709 if (get_one_authentic_pixel_from_handler !=
4710 (GetOneAuthenticPixelFromHandler) NULL)
4711 cache_info->methods.get_one_authentic_pixel_from_handler=
4712 cache_methods->get_one_authentic_pixel_from_handler;
4716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4720 + S e t P i x e l C a c h e N e x u s P i x e l s %
4724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4726 % SetPixelCacheNexusPixels() defines the region of the cache for the
4727 % specified cache nexus.
4729 % The format of the SetPixelCacheNexusPixels() method is:
4731 % Quantum SetPixelCacheNexusPixels(const Image *image,
4732 % const RectangleInfo *region,NexusInfo *nexus_info,
4733 % ExceptionInfo *exception)
4735 % A description of each parameter follows:
4737 % o image: the image.
4739 % o region: A pointer to the RectangleInfo structure that defines the
4740 % region of this particular cache nexus.
4742 % o nexus_info: the cache nexus to set.
4744 % o exception: return any errors or warnings in this structure.
4748 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4749 NexusInfo *nexus_info,ExceptionInfo *exception)
4751 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4752 return(MagickFalse);
4753 nexus_info->mapped=MagickFalse;
4754 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
4755 nexus_info->length);
4756 if (nexus_info->cache == (Quantum *) NULL)
4758 nexus_info->mapped=MagickTrue;
4759 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4760 nexus_info->length);
4762 if (nexus_info->cache == (Quantum *) NULL)
4764 (void) ThrowMagickException(exception,GetMagickModule(),
4765 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4766 cache_info->filename);
4767 return(MagickFalse);
4772 static Quantum *SetPixelCacheNexusPixels(const Image *image,
4773 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4785 cache_info=(CacheInfo *) image->cache;
4786 assert(cache_info->signature == MagickSignature);
4787 if (cache_info->type == UndefinedCache)
4788 return((Quantum *) NULL);
4789 nexus_info->region=(*region);
4790 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
4796 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4797 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4798 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4799 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4800 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4801 ((nexus_info->region.width == cache_info->columns) ||
4802 ((nexus_info->region.width % cache_info->columns) == 0)))))
4808 Pixels are accessed directly from memory.
4810 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4811 nexus_info->region.x;
4812 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4814 nexus_info->metacontent=(void *) NULL;
4815 if (cache_info->metacontent_extent != 0)
4816 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4817 offset*cache_info->metacontent_extent;
4818 return(nexus_info->pixels);
4822 Pixels are stored in a cache region until they are synced to the cache.
4824 number_pixels=(MagickSizeType) nexus_info->region.width*
4825 nexus_info->region.height;
4826 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4827 if (cache_info->metacontent_extent != 0)
4828 length+=number_pixels*cache_info->metacontent_extent;
4829 if (nexus_info->cache == (Quantum *) NULL)
4831 nexus_info->length=length;
4832 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4833 if (status == MagickFalse)
4835 nexus_info->length=0;
4836 return((Quantum *) NULL);
4840 if (nexus_info->length != length)
4842 RelinquishCacheNexusPixels(nexus_info);
4843 nexus_info->length=length;
4844 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4845 if (status == MagickFalse)
4847 nexus_info->length=0;
4848 return((Quantum *) NULL);
4851 nexus_info->pixels=nexus_info->cache;
4852 nexus_info->metacontent=(void *) NULL;
4853 if (cache_info->metacontent_extent != 0)
4854 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4855 cache_info->number_channels);
4856 return(nexus_info->pixels);
4860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4864 % 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 %
4868 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4870 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4871 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4872 % access that is outside the boundaries of the image cache.
4874 % The format of the SetPixelCacheVirtualMethod() method is:
4876 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4877 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4879 % A description of each parameter follows:
4881 % o image: the image.
4883 % o virtual_pixel_method: choose the type of virtual pixel.
4885 % o exception: return any errors or warnings in this structure.
4888 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4889 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4897 assert(image != (Image *) NULL);
4898 assert(image->signature == MagickSignature);
4899 if (image->debug != MagickFalse)
4900 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4901 assert(image->cache != (Cache) NULL);
4902 cache_info=(CacheInfo *) image->cache;
4903 assert(cache_info->signature == MagickSignature);
4904 method=cache_info->virtual_pixel_method;
4905 cache_info->virtual_pixel_method=virtual_pixel_method;
4906 switch (virtual_pixel_method)
4908 case BackgroundVirtualPixelMethod:
4910 if ((image->background_color.matte != MagickFalse) &&
4911 (image->matte == MagickFalse))
4912 (void) SetImageAlpha(image,OpaqueAlpha,exception);
4915 case TransparentVirtualPixelMethod:
4917 if (image->matte == MagickFalse)
4918 (void) SetImageAlpha(image,OpaqueAlpha,exception);
4928 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4932 + 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 %
4936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4938 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4939 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4940 % is synced, otherwise MagickFalse.
4942 % The format of the SyncAuthenticPixelCacheNexus() method is:
4944 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4945 % NexusInfo *nexus_info,ExceptionInfo *exception)
4947 % A description of each parameter follows:
4949 % o image: the image.
4951 % o nexus_info: the cache nexus to sync.
4953 % o exception: return any errors or warnings in this structure.
4956 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4957 NexusInfo *nexus_info,ExceptionInfo *exception)
4966 Transfer pixels to the cache.
4968 assert(image != (Image *) NULL);
4969 assert(image->signature == MagickSignature);
4970 if (image->cache == (Cache) NULL)
4971 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
4972 cache_info=(CacheInfo *) image->cache;
4973 assert(cache_info->signature == MagickSignature);
4974 if (cache_info->type == UndefinedCache)
4975 return(MagickFalse);
4976 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4978 assert(cache_info->signature == MagickSignature);
4979 status=WritePixelCachePixels(cache_info,nexus_info,exception);
4980 if ((cache_info->metacontent_extent != 0) &&
4981 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
4982 return(MagickFalse);
4987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4991 + S y n c A u t h e n t i c P i x e l C a c h e %
4995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4997 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
4998 % or disk cache. The method returns MagickTrue if the pixel region is synced,
4999 % otherwise MagickFalse.
5001 % The format of the SyncAuthenticPixelsCache() method is:
5003 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5004 % ExceptionInfo *exception)
5006 % A description of each parameter follows:
5008 % o image: the image.
5010 % o exception: return any errors or warnings in this structure.
5013 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5014 ExceptionInfo *exception)
5020 id = GetOpenMPThreadId();
5025 assert(image != (Image *) NULL);
5026 assert(image->signature == MagickSignature);
5027 assert(image->cache != (Cache) NULL);
5028 cache_info=(CacheInfo *) image->cache;
5029 assert(cache_info->signature == MagickSignature);
5030 assert(id < (int) cache_info->number_threads);
5031 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5041 % S y n c A u t h e n t i c P i x e l s %
5045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5047 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5048 % The method returns MagickTrue if the pixel region is flushed, otherwise
5051 % The format of the SyncAuthenticPixels() method is:
5053 % MagickBooleanType SyncAuthenticPixels(Image *image,
5054 % ExceptionInfo *exception)
5056 % A description of each parameter follows:
5058 % o image: the image.
5060 % o exception: return any errors or warnings in this structure.
5063 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5064 ExceptionInfo *exception)
5070 id = GetOpenMPThreadId();
5075 assert(image != (Image *) NULL);
5076 assert(image->signature == MagickSignature);
5077 assert(image->cache != (Cache) NULL);
5078 cache_info=(CacheInfo *) image->cache;
5079 assert(cache_info->signature == MagickSignature);
5080 if (cache_info->methods.sync_authentic_pixels_handler !=
5081 (SyncAuthenticPixelsHandler) NULL)
5083 status=cache_info->methods.sync_authentic_pixels_handler(image,
5087 assert(id < (int) cache_info->number_threads);
5088 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5098 + S y n c I m a g e P i x e l C a c h e %
5102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5104 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5105 % The method returns MagickTrue if the pixel region is flushed, otherwise
5108 % The format of the SyncImagePixelCache() method is:
5110 % MagickBooleanType SyncImagePixelCache(Image *image,
5111 % ExceptionInfo *exception)
5113 % A description of each parameter follows:
5115 % o image: the image.
5117 % o exception: return any errors or warnings in this structure.
5120 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5121 ExceptionInfo *exception)
5126 assert(image != (Image *) NULL);
5127 assert(exception != (ExceptionInfo *) NULL);
5128 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5129 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5137 + 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 %
5141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5143 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5144 % of the pixel cache.
5146 % The format of the WritePixelCacheMetacontent() method is:
5148 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5149 % NexusInfo *nexus_info,ExceptionInfo *exception)
5151 % A description of each parameter follows:
5153 % o cache_info: the pixel cache.
5155 % o nexus_info: the cache nexus to write the meta-content.
5157 % o exception: return any errors or warnings in this structure.
5160 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5161 NexusInfo *nexus_info,ExceptionInfo *exception)
5171 register const unsigned char
5180 if (cache_info->metacontent_extent == 0)
5181 return(MagickFalse);
5182 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5184 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5185 nexus_info->region.x;
5186 length=(MagickSizeType) nexus_info->region.width*
5187 cache_info->metacontent_extent;
5188 rows=nexus_info->region.height;
5189 extent=(MagickSizeType) length*rows;
5190 p=(unsigned char *) nexus_info->metacontent;
5191 switch (cache_info->type)
5196 register unsigned char
5200 Write associated pixels to memory.
5202 if ((cache_info->columns == nexus_info->region.width) &&
5203 (extent == (MagickSizeType) ((size_t) extent)))
5208 q=(unsigned char *) cache_info->metacontent+offset*
5209 cache_info->metacontent_extent;
5210 for (y=0; y < (ssize_t) rows; y++)
5212 (void) memcpy(q,p,(size_t) length);
5213 p+=nexus_info->region.width*cache_info->metacontent_extent;
5214 q+=cache_info->columns*cache_info->metacontent_extent;
5221 Write associated pixels to disk.
5223 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5225 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5226 cache_info->cache_filename);
5227 return(MagickFalse);
5229 if ((cache_info->columns == nexus_info->region.width) &&
5230 (extent <= MagickMaxBufferExtent))
5235 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5236 for (y=0; y < (ssize_t) rows; y++)
5238 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5239 cache_info->number_channels*sizeof(Quantum)+offset*
5240 cache_info->metacontent_extent,length,(const unsigned char *) p);
5241 if ((MagickSizeType) count != length)
5243 p+=nexus_info->region.width*cache_info->metacontent_extent;
5244 offset+=cache_info->columns;
5246 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5247 (void) ClosePixelCacheOnDisk(cache_info);
5248 if (y < (ssize_t) rows)
5250 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5251 cache_info->cache_filename);
5252 return(MagickFalse);
5259 if ((cache_info->debug != MagickFalse) &&
5260 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5261 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5262 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5263 nexus_info->region.width,(double) nexus_info->region.height,(double)
5264 nexus_info->region.x,(double) nexus_info->region.y);
5269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5273 + W r i t e C a c h e P i x e l s %
5277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5279 % WritePixelCachePixels() writes image pixels to the specified region of the
5282 % The format of the WritePixelCachePixels() method is:
5284 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5285 % NexusInfo *nexus_info,ExceptionInfo *exception)
5287 % A description of each parameter follows:
5289 % o cache_info: the pixel cache.
5291 % o nexus_info: the cache nexus to write the pixels.
5293 % o exception: return any errors or warnings in this structure.
5296 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5297 NexusInfo *nexus_info,ExceptionInfo *exception)
5307 register const Quantum
5316 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5318 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5319 nexus_info->region.x;
5320 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5322 rows=nexus_info->region.height;
5324 p=nexus_info->pixels;
5325 switch (cache_info->type)
5334 Write pixels to memory.
5336 if ((cache_info->columns == nexus_info->region.width) &&
5337 (extent == (MagickSizeType) ((size_t) extent)))
5342 q=cache_info->pixels+offset*cache_info->number_channels;
5343 for (y=0; y < (ssize_t) rows; y++)
5345 (void) memcpy(q,p,(size_t) length);
5346 p+=nexus_info->region.width*cache_info->number_channels;
5347 q+=cache_info->columns*cache_info->number_channels;
5354 Write pixels to disk.
5356 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5358 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5359 cache_info->cache_filename);
5360 return(MagickFalse);
5362 if ((cache_info->columns == nexus_info->region.width) &&
5363 (extent <= MagickMaxBufferExtent))
5368 for (y=0; y < (ssize_t) rows; y++)
5370 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5371 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5373 if ((MagickSizeType) count != length)
5375 p+=nexus_info->region.width*cache_info->number_channels;
5376 offset+=cache_info->columns;
5378 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5379 (void) ClosePixelCacheOnDisk(cache_info);
5380 if (y < (ssize_t) rows)
5382 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5383 cache_info->cache_filename);
5384 return(MagickFalse);
5391 if ((cache_info->debug != MagickFalse) &&
5392 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5393 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5394 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5395 nexus_info->region.width,(double) nexus_info->region.height,(double)
5396 nexus_info->region.x,(double) nexus_info->region.y);