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/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/exception.h"
52 #include "MagickCore/exception-private.h"
53 #include "MagickCore/geometry.h"
54 #include "MagickCore/list.h"
55 #include "MagickCore/log.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/memory-private.h"
59 #include "MagickCore/nt-base-private.h"
60 #include "MagickCore/pixel.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/policy.h"
63 #include "MagickCore/quantum.h"
64 #include "MagickCore/random_.h"
65 #include "MagickCore/resource_.h"
66 #include "MagickCore/semaphore.h"
67 #include "MagickCore/splay-tree.h"
68 #include "MagickCore/string_.h"
69 #include "MagickCore/string-private.h"
70 #include "MagickCore/thread-private.h"
71 #include "MagickCore/utility.h"
72 #include "MagickCore/utility-private.h"
73 #if defined(MAGICKCORE_ZLIB_DELEGATE)
80 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
81 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
82 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
87 typedef struct _MagickModulo
117 Forward declarations.
119 #if defined(__cplusplus) || defined(c_plusplus)
124 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
128 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
129 const ssize_t,const size_t,const size_t,ExceptionInfo *),
130 *GetVirtualPixelsCache(const Image *);
133 *GetVirtualMetacontentFromCache(const Image *);
135 static MagickBooleanType
136 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
138 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
139 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
140 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
141 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
142 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
143 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
144 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
145 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
148 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
149 const size_t,ExceptionInfo *),
150 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
151 const size_t,ExceptionInfo *),
152 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
153 NexusInfo *,ExceptionInfo *) magick_hot_spot;
155 #if defined(__cplusplus) || defined(c_plusplus)
162 static volatile MagickBooleanType
163 instantiate_cache = MagickFalse;
166 *cache_semaphore = (SemaphoreInfo *) NULL;
169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173 + A c q u i r e P i x e l C a c h e %
177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
179 % AcquirePixelCache() acquires a pixel cache.
181 % The format of the AcquirePixelCache() method is:
183 % Cache AcquirePixelCache(const size_t number_threads)
185 % A description of each parameter follows:
187 % o number_threads: the number of nexus threads.
190 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
195 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
196 if (cache_info == (CacheInfo *) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
199 cache_info->type=UndefinedCache;
200 cache_info->mode=IOMode;
201 cache_info->colorspace=sRGBColorspace;
202 cache_info->file=(-1);
203 cache_info->id=GetMagickThreadId();
204 cache_info->number_threads=number_threads;
205 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
206 cache_info->number_threads=GetOpenMPMaximumThreads();
207 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
208 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
209 if (cache_info->number_threads == 0)
210 cache_info->number_threads=1;
211 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
212 if (cache_info->nexus_info == (NexusInfo **) NULL)
213 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
214 cache_info->semaphore=AllocateSemaphoreInfo();
215 cache_info->reference_count=1;
216 cache_info->disk_semaphore=AllocateSemaphoreInfo();
217 cache_info->debug=IsEventLogging();
218 cache_info->signature=MagickSignature;
219 return((Cache ) cache_info);
223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227 % A c q u i r e P i x e l C a c h e N e x u s %
231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
235 % The format of the AcquirePixelCacheNexus method is:
237 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
239 % A description of each parameter follows:
241 % o number_threads: the number of nexus threads.
244 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
252 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
253 number_threads,sizeof(*nexus_info)));
254 if (nexus_info == (NexusInfo **) NULL)
255 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
256 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
257 sizeof(**nexus_info));
258 if (nexus_info[0] == (NexusInfo *) NULL)
259 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
260 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
261 for (i=0; i < (ssize_t) number_threads; i++)
263 nexus_info[i]=(&nexus_info[0][i]);
264 nexus_info[i]->signature=MagickSignature;
270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 + A c q u i r e P i x e l C a c h e P i x e l s %
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 % AcquirePixelCachePixels() returns the pixels associated with the specified
283 % The format of the AcquirePixelCachePixels() method is:
285 % const void *AcquirePixelCachePixels(const Image *image,
286 % MagickSizeType *length,ExceptionInfo *exception)
288 % A description of each parameter follows:
290 % o image: the image.
292 % o length: the pixel cache length.
294 % o exception: return any errors or warnings in this structure.
297 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
298 MagickSizeType *length,ExceptionInfo *exception)
303 assert(image != (const Image *) NULL);
304 assert(image->signature == MagickSignature);
305 assert(exception != (ExceptionInfo *) NULL);
306 assert(exception->signature == MagickSignature);
307 assert(image->cache != (Cache) NULL);
308 cache_info=(CacheInfo *) image->cache;
309 assert(cache_info->signature == MagickSignature);
311 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
312 return((const void *) NULL);
313 *length=cache_info->length;
314 return((const void *) cache_info->pixels);
318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322 + C a c h e C o m p o n e n t G e n e s i s %
326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328 % CacheComponentGenesis() instantiates the cache component.
330 % The format of the CacheComponentGenesis method is:
332 % MagickBooleanType CacheComponentGenesis(void)
335 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
337 AcquireSemaphoreInfo(&cache_semaphore);
342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 + C a c h e C o m p o n e n t T e r m i n u s %
350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
352 % CacheComponentTerminus() destroys the cache component.
354 % The format of the CacheComponentTerminus() method is:
356 % CacheComponentTerminus(void)
359 MagickPrivate void CacheComponentTerminus(void)
361 if (cache_semaphore == (SemaphoreInfo *) NULL)
362 AcquireSemaphoreInfo(&cache_semaphore);
363 LockSemaphoreInfo(cache_semaphore);
364 instantiate_cache=MagickFalse;
365 UnlockSemaphoreInfo(cache_semaphore);
366 DestroySemaphoreInfo(&cache_semaphore);
370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 + C l o n e P i x e l C a c h e %
378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380 % ClonePixelCache() clones a pixel cache.
382 % The format of the ClonePixelCache() method is:
384 % Cache ClonePixelCache(const Cache cache)
386 % A description of each parameter follows:
388 % o cache: the pixel cache.
391 MagickPrivate Cache ClonePixelCache(const Cache cache)
399 assert(cache != NULL);
400 cache_info=(const CacheInfo *) cache;
401 assert(cache_info->signature == MagickSignature);
402 if (cache_info->debug != MagickFalse)
403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
404 cache_info->filename);
405 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
406 if (clone_info == (Cache) NULL)
407 return((Cache) NULL);
408 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
409 return((Cache ) clone_info);
413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
417 + C l o n e P i x e l C a c h e P i x e l s %
421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
422 % ClonePixelCachePixels() clones the source pixel cache to the destination
425 % The format of the ClonePixelCachePixels() method is:
427 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
428 % CacheInfo *source_info,ExceptionInfo *exception)
430 % A description of each parameter follows:
432 % o cache_info: the pixel cache.
434 % o source_info: the source pixel cache.
436 % o exception: return any errors or warnings in this structure.
440 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
446 LockSemaphoreInfo(cache_info->disk_semaphore);
447 if (cache_info->file != -1)
449 status=close(cache_info->file);
450 cache_info->file=(-1);
451 RelinquishMagickResource(FileResource,1);
453 UnlockSemaphoreInfo(cache_info->disk_semaphore);
454 return(status == -1 ? MagickFalse : MagickTrue);
457 static inline MagickSizeType MagickMax(const MagickSizeType x,
458 const MagickSizeType y)
465 static inline MagickSizeType MagickMin(const MagickSizeType x,
466 const MagickSizeType y)
473 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
480 Open pixel cache on disk.
482 LockSemaphoreInfo(cache_info->disk_semaphore);
483 if (cache_info->file != -1)
485 UnlockSemaphoreInfo(cache_info->disk_semaphore);
486 return(MagickTrue); /* cache already open */
488 if (*cache_info->cache_filename == '\0')
489 file=AcquireUniqueFileResource(cache_info->cache_filename);
495 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
500 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
501 O_BINARY | O_EXCL,S_MODE);
503 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
509 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
512 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
518 UnlockSemaphoreInfo(cache_info->disk_semaphore);
521 (void) AcquireMagickResource(FileResource,1);
522 cache_info->file=file;
523 cache_info->mode=mode;
524 UnlockSemaphoreInfo(cache_info->disk_semaphore);
528 static inline MagickOffsetType ReadPixelCacheRegion(
529 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
530 const MagickSizeType length,unsigned char *restrict buffer)
532 register MagickOffsetType
538 #if !defined(MAGICKCORE_HAVE_PREAD)
539 LockSemaphoreInfo(cache_info->disk_semaphore);
540 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
542 UnlockSemaphoreInfo(cache_info->disk_semaphore);
543 return((MagickOffsetType) -1);
547 for (i=0; i < (MagickOffsetType) length; i+=count)
549 #if !defined(MAGICKCORE_HAVE_PREAD)
550 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
551 (MagickSizeType) SSIZE_MAX));
553 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
554 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
563 #if !defined(MAGICKCORE_HAVE_PREAD)
564 UnlockSemaphoreInfo(cache_info->disk_semaphore);
569 static inline MagickOffsetType WritePixelCacheRegion(
570 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
571 const MagickSizeType length,const unsigned char *restrict buffer)
573 register MagickOffsetType
579 #if !defined(MAGICKCORE_HAVE_PWRITE)
580 LockSemaphoreInfo(cache_info->disk_semaphore);
581 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
583 UnlockSemaphoreInfo(cache_info->disk_semaphore);
584 return((MagickOffsetType) -1);
588 for (i=0; i < (MagickOffsetType) length; i+=count)
590 #if !defined(MAGICKCORE_HAVE_PWRITE)
591 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
592 (MagickSizeType) SSIZE_MAX));
594 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
595 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
604 #if !defined(MAGICKCORE_HAVE_PWRITE)
605 UnlockSemaphoreInfo(cache_info->disk_semaphore);
610 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
611 CacheInfo *cache_info,ExceptionInfo *exception)
616 register MagickOffsetType
626 Clone pixel cache (both caches on disk).
628 if (cache_info->debug != MagickFalse)
629 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
630 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
632 if (blob == (unsigned char *) NULL)
634 (void) ThrowMagickException(exception,GetMagickModule(),
635 ResourceLimitError,"MemoryAllocationFailed","'%s'",
636 cache_info->filename);
639 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
641 blob=(unsigned char *) RelinquishMagickMemory(blob);
642 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
643 cache_info->cache_filename);
646 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
648 (void) ClosePixelCacheOnDisk(cache_info);
649 blob=(unsigned char *) RelinquishMagickMemory(blob);
650 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
651 clone_info->cache_filename);
655 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
657 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
658 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
662 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
663 cache_info->cache_filename);
666 length=(size_t) count;
667 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
668 if ((MagickSizeType) count != length)
670 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
671 clone_info->cache_filename);
675 (void) ClosePixelCacheOnDisk(clone_info);
676 (void) ClosePixelCacheOnDisk(cache_info);
677 blob=(unsigned char *) RelinquishMagickMemory(blob);
678 if (i < (MagickOffsetType) cache_info->length)
683 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
684 CacheInfo *cache_info,ExceptionInfo *exception)
689 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
692 Clone pixel cache (both caches in memory).
694 if (cache_info->debug != MagickFalse)
695 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
696 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
700 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
703 Clone pixel cache (one cache on disk, one in memory).
705 if (cache_info->debug != MagickFalse)
706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
707 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
709 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
710 cache_info->cache_filename);
713 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
714 cache_info->length,(unsigned char *) clone_info->pixels);
715 (void) ClosePixelCacheOnDisk(cache_info);
716 if ((MagickSizeType) count != cache_info->length)
718 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
719 cache_info->cache_filename);
724 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
727 Clone pixel cache (one cache on disk, one in memory).
729 if (clone_info->debug != MagickFalse)
730 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
731 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
733 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
734 clone_info->cache_filename);
737 count=WritePixelCacheRegion(clone_info,clone_info->offset,
738 clone_info->length,(unsigned char *) cache_info->pixels);
739 (void) ClosePixelCacheOnDisk(clone_info);
740 if ((MagickSizeType) count != clone_info->length)
742 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
743 clone_info->cache_filename);
749 Clone pixel cache (both caches on disk).
751 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
754 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
755 CacheInfo *cache_info,ExceptionInfo *exception)
768 register unsigned char
781 Clone pixel cache (unoptimized).
783 if (cache_info->debug != MagickFalse)
785 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
788 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
789 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
791 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
792 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
794 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
796 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
797 clone_info->number_channels)*sizeof(Quantum),MagickMax(
798 cache_info->metacontent_extent,clone_info->metacontent_extent));
799 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
800 if (blob == (unsigned char *) NULL)
802 (void) ThrowMagickException(exception,GetMagickModule(),
803 ResourceLimitError,"MemoryAllocationFailed","'%s'",
804 cache_info->filename);
807 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
810 if (cache_info->type == DiskCache)
812 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
814 blob=(unsigned char *) RelinquishMagickMemory(blob);
815 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
816 cache_info->cache_filename);
819 cache_offset=cache_info->offset;
821 if (clone_info->type == DiskCache)
823 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
825 blob=(unsigned char *) RelinquishMagickMemory(blob);
826 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
827 clone_info->cache_filename);
830 clone_offset=clone_info->offset;
833 Clone pixel channels.
837 for (y=0; y < (ssize_t) cache_info->rows; y++)
839 for (x=0; x < (ssize_t) cache_info->columns; x++)
845 Read a set of pixel channels.
847 length=cache_info->number_channels*sizeof(Quantum);
848 if (cache_info->type != DiskCache)
849 p=(unsigned char *) cache_info->pixels+cache_offset;
852 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
853 if ((MagickSizeType) count != length)
859 cache_offset+=length;
860 if ((y < (ssize_t) clone_info->rows) &&
861 (x < (ssize_t) clone_info->columns))
862 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
874 Write a set of pixel channels.
876 channel=clone_info->channel_map[i].channel;
877 traits=cache_info->channel_map[channel].traits;
878 if (traits == UndefinedPixelTrait)
880 clone_offset+=sizeof(Quantum);
883 offset=cache_info->channel_map[channel].offset;
884 if (clone_info->type != DiskCache)
885 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
886 offset*sizeof(Quantum),sizeof(Quantum));
889 count=WritePixelCacheRegion(clone_info,clone_offset,
890 sizeof(Quantum),p+offset*sizeof(Quantum));
891 if ((MagickSizeType) count != sizeof(Quantum))
897 clone_offset+=sizeof(Quantum);
900 if (y < (ssize_t) clone_info->rows)
903 Set remaining columns as undefined.
905 length=clone_info->number_channels*sizeof(Quantum);
906 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
907 for ( ; x < (ssize_t) clone_info->columns; x++)
909 if (clone_info->type != DiskCache)
910 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
914 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
915 if ((MagickSizeType) count != length)
921 clone_offset+=length;
925 length=clone_info->number_channels*sizeof(Quantum);
926 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
927 for ( ; y < (ssize_t) clone_info->rows; y++)
930 Set remaining rows as undefined.
932 for (x=0; x < (ssize_t) clone_info->columns; x++)
934 if (clone_info->type != DiskCache)
935 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
939 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
940 if ((MagickSizeType) count != length)
946 clone_offset+=length;
949 if ((cache_info->metacontent_extent != 0) ||
950 (clone_info->metacontent_extent != 0))
955 for (y=0; y < (ssize_t) cache_info->rows; y++)
957 for (x=0; x < (ssize_t) cache_info->columns; x++)
960 Read a set of metacontent.
962 length=cache_info->metacontent_extent;
963 if (cache_info->type != DiskCache)
964 p=(unsigned char *) cache_info->pixels+cache_offset;
967 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
968 if ((MagickSizeType) count != length)
974 cache_offset+=length;
975 if ((y < (ssize_t) clone_info->rows) &&
976 (x < (ssize_t) clone_info->columns))
979 Write a set of metacontent.
981 length=clone_info->metacontent_extent;
982 if (clone_info->type != DiskCache)
983 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
987 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
988 if ((MagickSizeType) count != length)
994 clone_offset+=length;
997 length=clone_info->metacontent_extent;
998 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
999 for ( ; x < (ssize_t) clone_info->columns; x++)
1002 Set remaining columns as undefined.
1004 if (clone_info->type != DiskCache)
1005 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1009 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1010 if ((MagickSizeType) count != length)
1016 clone_offset+=length;
1019 if (y < (ssize_t) clone_info->rows)
1022 Set remaining rows as undefined.
1024 length=clone_info->metacontent_extent;
1025 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1026 for ( ; y < (ssize_t) clone_info->rows; y++)
1028 for (x=0; x < (ssize_t) clone_info->columns; x++)
1030 if (clone_info->type != DiskCache)
1031 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1035 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1037 if ((MagickSizeType) count != length)
1043 clone_offset+=length;
1048 if (clone_info->type == DiskCache)
1049 (void) ClosePixelCacheOnDisk(clone_info);
1050 if (cache_info->type == DiskCache)
1051 (void) ClosePixelCacheOnDisk(cache_info);
1052 blob=(unsigned char *) RelinquishMagickMemory(blob);
1056 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1057 CacheInfo *cache_info,ExceptionInfo *exception)
1063 if (cache_info->type == PingCache)
1065 p=cache_info->channel_map;
1066 q=clone_info->channel_map;
1067 if ((cache_info->columns == clone_info->columns) &&
1068 (cache_info->rows == clone_info->rows) &&
1069 (cache_info->number_channels == clone_info->number_channels) &&
1070 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1071 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1072 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1073 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081 + C l o n e P i x e l C a c h e M e t h o d s %
1085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1090 % The format of the ClonePixelCacheMethods() method is:
1092 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1094 % A description of each parameter follows:
1096 % o clone: Specifies a pointer to a Cache structure.
1098 % o cache: the pixel cache.
1101 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1107 assert(clone != (Cache) NULL);
1108 source_info=(CacheInfo *) clone;
1109 assert(source_info->signature == MagickSignature);
1110 if (source_info->debug != MagickFalse)
1111 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1112 source_info->filename);
1113 assert(cache != (Cache) NULL);
1114 cache_info=(CacheInfo *) cache;
1115 assert(cache_info->signature == MagickSignature);
1116 source_info->methods=cache_info->methods;
1120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1124 + D e s t r o y I m a g e P i x e l C a c h e %
1128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1130 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1132 % The format of the DestroyImagePixelCache() method is:
1134 % void DestroyImagePixelCache(Image *image)
1136 % A description of each parameter follows:
1138 % o image: the image.
1141 static void DestroyImagePixelCache(Image *image)
1143 assert(image != (Image *) NULL);
1144 assert(image->signature == MagickSignature);
1145 if (image->debug != MagickFalse)
1146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1147 if (image->cache == (void *) NULL)
1149 image->cache=DestroyPixelCache(image->cache);
1153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1157 + D e s t r o y I m a g e P i x e l s %
1161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1163 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1165 % The format of the DestroyImagePixels() method is:
1167 % void DestroyImagePixels(Image *image)
1169 % A description of each parameter follows:
1171 % o image: the image.
1174 MagickExport void DestroyImagePixels(Image *image)
1179 assert(image != (const Image *) NULL);
1180 assert(image->signature == MagickSignature);
1181 if (image->debug != MagickFalse)
1182 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1183 assert(image->cache != (Cache) NULL);
1184 cache_info=(CacheInfo *) image->cache;
1185 assert(cache_info->signature == MagickSignature);
1186 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1188 cache_info->methods.destroy_pixel_handler(image);
1191 image->cache=DestroyPixelCache(image->cache);
1195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199 + D e s t r o y P i x e l C a c h e %
1203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1207 % The format of the DestroyPixelCache() method is:
1209 % Cache DestroyPixelCache(Cache cache)
1211 % A description of each parameter follows:
1213 % o cache: the pixel cache.
1217 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1219 switch (cache_info->type)
1223 if (cache_info->mapped == MagickFalse)
1224 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
1225 cache_info->pixels);
1227 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1228 (size_t) cache_info->length);
1229 RelinquishMagickResource(MemoryResource,cache_info->length);
1234 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1235 cache_info->length);
1236 RelinquishMagickResource(MapResource,cache_info->length);
1240 if (cache_info->file != -1)
1241 (void) ClosePixelCacheOnDisk(cache_info);
1242 RelinquishMagickResource(DiskResource,cache_info->length);
1248 cache_info->type=UndefinedCache;
1249 cache_info->mapped=MagickFalse;
1250 cache_info->metacontent=(void *) NULL;
1253 MagickPrivate Cache DestroyPixelCache(Cache cache)
1258 assert(cache != (Cache) NULL);
1259 cache_info=(CacheInfo *) cache;
1260 assert(cache_info->signature == MagickSignature);
1261 if (cache_info->debug != MagickFalse)
1262 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1263 cache_info->filename);
1264 LockSemaphoreInfo(cache_info->semaphore);
1265 cache_info->reference_count--;
1266 if (cache_info->reference_count != 0)
1268 UnlockSemaphoreInfo(cache_info->semaphore);
1269 return((Cache) NULL);
1271 UnlockSemaphoreInfo(cache_info->semaphore);
1272 if (cache_info->debug != MagickFalse)
1275 message[MaxTextExtent];
1277 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1278 cache_info->filename);
1279 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1281 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1282 (cache_info->type != DiskCache)))
1283 RelinquishPixelCachePixels(cache_info);
1286 RelinquishPixelCachePixels(cache_info);
1287 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1289 *cache_info->cache_filename='\0';
1290 if (cache_info->nexus_info != (NexusInfo **) NULL)
1291 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1292 cache_info->number_threads);
1293 if (cache_info->random_info != (RandomInfo *) NULL)
1294 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1295 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1296 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1297 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1298 DestroySemaphoreInfo(&cache_info->semaphore);
1299 cache_info->signature=(~MagickSignature);
1300 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310 + D e s t r o y P i x e l C a c h e N e x u s %
1314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1316 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1318 % The format of the DestroyPixelCacheNexus() method is:
1320 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1321 % const size_t number_threads)
1323 % A description of each parameter follows:
1325 % o nexus_info: the nexus to destroy.
1327 % o number_threads: the number of nexus threads.
1331 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1333 if (nexus_info->mapped == MagickFalse)
1334 (void) RelinquishAlignedMemory(nexus_info->cache);
1336 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1337 nexus_info->cache=(Quantum *) NULL;
1338 nexus_info->pixels=(Quantum *) NULL;
1339 nexus_info->metacontent=(void *) NULL;
1340 nexus_info->length=0;
1341 nexus_info->mapped=MagickFalse;
1344 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1345 const size_t number_threads)
1350 assert(nexus_info != (NexusInfo **) NULL);
1351 for (i=0; i < (ssize_t) number_threads; i++)
1353 if (nexus_info[i]->cache != (Quantum *) NULL)
1354 RelinquishCacheNexusPixels(nexus_info[i]);
1355 nexus_info[i]->signature=(~MagickSignature);
1357 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1358 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1367 % G e t A u t h e n t i c M e t a c o n t e n t %
1371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1373 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1374 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1375 % returned if the associated pixels are not available.
1377 % The format of the GetAuthenticMetacontent() method is:
1379 % void *GetAuthenticMetacontent(const Image *image)
1381 % A description of each parameter follows:
1383 % o image: the image.
1386 MagickExport void *GetAuthenticMetacontent(const Image *image)
1392 id = GetOpenMPThreadId();
1397 assert(image != (const Image *) NULL);
1398 assert(image->signature == MagickSignature);
1399 assert(image->cache != (Cache) NULL);
1400 cache_info=(CacheInfo *) image->cache;
1401 assert(cache_info->signature == MagickSignature);
1402 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1403 (GetAuthenticMetacontentFromHandler) NULL)
1405 metacontent=cache_info->methods.
1406 get_authentic_metacontent_from_handler(image);
1407 return(metacontent);
1409 assert(id < (int) cache_info->number_threads);
1410 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1411 cache_info->nexus_info[id]);
1412 return(metacontent);
1416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420 + 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 %
1424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1427 % with the last call to QueueAuthenticPixelsCache() or
1428 % GetAuthenticPixelsCache().
1430 % The format of the GetAuthenticMetacontentFromCache() method is:
1432 % void *GetAuthenticMetacontentFromCache(const Image *image)
1434 % A description of each parameter follows:
1436 % o image: the image.
1439 static void *GetAuthenticMetacontentFromCache(const Image *image)
1445 id = GetOpenMPThreadId();
1450 assert(image != (const Image *) NULL);
1451 assert(image->signature == MagickSignature);
1452 assert(image->cache != (Cache) NULL);
1453 cache_info=(CacheInfo *) image->cache;
1454 assert(cache_info->signature == MagickSignature);
1455 assert(id < (int) cache_info->number_threads);
1456 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1457 cache_info->nexus_info[id]);
1458 return(metacontent);
1462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1466 + 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 %
1470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1472 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1473 % disk pixel cache as defined by the geometry parameters. A pointer to the
1474 % pixels is returned if the pixels are transferred, otherwise a NULL is
1477 % The format of the GetAuthenticPixelCacheNexus() method is:
1479 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1480 % const ssize_t y,const size_t columns,const size_t rows,
1481 % NexusInfo *nexus_info,ExceptionInfo *exception)
1483 % A description of each parameter follows:
1485 % o image: the image.
1487 % o x,y,columns,rows: These values define the perimeter of a region of
1490 % o nexus_info: the cache nexus to return.
1492 % o exception: return any errors or warnings in this structure.
1496 static inline MagickBooleanType IsPixelAuthentic(
1497 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1505 if (cache_info->type == PingCache)
1507 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1508 nexus_info->region.x;
1509 status=nexus_info->pixels == (cache_info->pixels+offset*
1510 cache_info->number_channels) ? MagickTrue : MagickFalse;
1514 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1515 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1516 NexusInfo *nexus_info,ExceptionInfo *exception)
1525 Transfer pixels from the cache.
1527 assert(image != (Image *) NULL);
1528 assert(image->signature == MagickSignature);
1529 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1531 if (q == (Quantum *) NULL)
1532 return((Quantum *) NULL);
1533 cache_info=(CacheInfo *) image->cache;
1534 assert(cache_info->signature == MagickSignature);
1535 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1537 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1538 return((Quantum *) NULL);
1539 if (cache_info->metacontent_extent != 0)
1540 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1541 return((Quantum *) NULL);
1546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1550 + 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 %
1554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1557 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1559 % The format of the GetAuthenticPixelsFromCache() method is:
1561 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1563 % A description of each parameter follows:
1565 % o image: the image.
1568 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1574 id = GetOpenMPThreadId();
1576 assert(image != (const Image *) NULL);
1577 assert(image->signature == MagickSignature);
1578 assert(image->cache != (Cache) NULL);
1579 cache_info=(CacheInfo *) image->cache;
1580 assert(cache_info->signature == MagickSignature);
1581 assert(id < (int) cache_info->number_threads);
1582 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590 % G e t A u t h e n t i c P i x e l Q u e u e %
1594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596 % GetAuthenticPixelQueue() returns the authentic pixels associated
1597 % corresponding with the last call to QueueAuthenticPixels() or
1598 % GetAuthenticPixels().
1600 % The format of the GetAuthenticPixelQueue() method is:
1602 % Quantum *GetAuthenticPixelQueue(const Image image)
1604 % A description of each parameter follows:
1606 % o image: the image.
1609 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1615 id = GetOpenMPThreadId();
1617 assert(image != (const Image *) NULL);
1618 assert(image->signature == MagickSignature);
1619 assert(image->cache != (Cache) NULL);
1620 cache_info=(CacheInfo *) image->cache;
1621 assert(cache_info->signature == MagickSignature);
1622 if (cache_info->methods.get_authentic_pixels_from_handler !=
1623 (GetAuthenticPixelsFromHandler) NULL)
1624 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1625 assert(id < (int) cache_info->number_threads);
1626 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1634 % G e t A u t h e n t i c P i x e l s %
1637 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1640 % region is successfully accessed, a pointer to a Quantum array
1641 % representing the region is returned, otherwise NULL is returned.
1643 % The returned pointer may point to a temporary working copy of the pixels
1644 % or it may point to the original pixels in memory. Performance is maximized
1645 % if the selected region is part of one row, or one or more full rows, since
1646 % then there is opportunity to access the pixels in-place (without a copy)
1647 % if the image is in memory, or in a memory-mapped file. The returned pointer
1648 % must *never* be deallocated by the user.
1650 % Pixels accessed via the returned pointer represent a simple array of type
1651 % Quantum. If the image has corresponding metacontent,call
1652 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1653 % meta-content corresponding to the region. Once the Quantum array has
1654 % been updated, the changes must be saved back to the underlying image using
1655 % SyncAuthenticPixels() or they may be lost.
1657 % The format of the GetAuthenticPixels() method is:
1659 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1660 % const ssize_t y,const size_t columns,const size_t rows,
1661 % ExceptionInfo *exception)
1663 % A description of each parameter follows:
1665 % o image: the image.
1667 % o x,y,columns,rows: These values define the perimeter of a region of
1670 % o exception: return any errors or warnings in this structure.
1673 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1674 const ssize_t y,const size_t columns,const size_t rows,
1675 ExceptionInfo *exception)
1681 id = GetOpenMPThreadId();
1686 assert(image != (Image *) NULL);
1687 assert(image->signature == MagickSignature);
1688 assert(image->cache != (Cache) NULL);
1689 cache_info=(CacheInfo *) image->cache;
1690 assert(cache_info->signature == MagickSignature);
1691 if (cache_info->methods.get_authentic_pixels_handler !=
1692 (GetAuthenticPixelsHandler) NULL)
1694 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1698 assert(id < (int) cache_info->number_threads);
1699 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1700 cache_info->nexus_info[id],exception);
1705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1709 + G e t A u t h e n t i c P i x e l s C a c h e %
1713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1715 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1716 % as defined by the geometry parameters. A pointer to the pixels is returned
1717 % if the pixels are transferred, otherwise a NULL is returned.
1719 % The format of the GetAuthenticPixelsCache() method is:
1721 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1722 % const ssize_t y,const size_t columns,const size_t rows,
1723 % ExceptionInfo *exception)
1725 % A description of each parameter follows:
1727 % o image: the image.
1729 % o x,y,columns,rows: These values define the perimeter of a region of
1732 % o exception: return any errors or warnings in this structure.
1735 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1736 const ssize_t y,const size_t columns,const size_t rows,
1737 ExceptionInfo *exception)
1743 id = GetOpenMPThreadId();
1748 assert(image != (const Image *) NULL);
1749 assert(image->signature == MagickSignature);
1750 assert(image->cache != (Cache) NULL);
1751 cache_info=(CacheInfo *) image->cache;
1752 if (cache_info == (Cache) NULL)
1753 return((Quantum *) NULL);
1754 assert(cache_info->signature == MagickSignature);
1755 assert(id < (int) cache_info->number_threads);
1756 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1757 cache_info->nexus_info[id],exception);
1762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1766 + G e t I m a g e E x t e n t %
1770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1772 % GetImageExtent() returns the extent of the pixels associated corresponding
1773 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1775 % The format of the GetImageExtent() method is:
1777 % MagickSizeType GetImageExtent(const Image *image)
1779 % A description of each parameter follows:
1781 % o image: the image.
1784 MagickExport MagickSizeType GetImageExtent(const Image *image)
1790 id = GetOpenMPThreadId();
1792 assert(image != (Image *) NULL);
1793 assert(image->signature == MagickSignature);
1794 if (image->debug != MagickFalse)
1795 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1796 assert(image->cache != (Cache) NULL);
1797 cache_info=(CacheInfo *) image->cache;
1798 assert(cache_info->signature == MagickSignature);
1799 assert(id < (int) cache_info->number_threads);
1800 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1808 + G e t I m a g e P i x e l C a c h e %
1812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1814 % GetImagePixelCache() ensures that there is only a single reference to the
1815 % pixel cache to be modified, updating the provided cache pointer to point to
1816 % a clone of the original pixel cache if necessary.
1818 % The format of the GetImagePixelCache method is:
1820 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1821 % ExceptionInfo *exception)
1823 % A description of each parameter follows:
1825 % o image: the image.
1827 % o clone: any value other than MagickFalse clones the cache pixels.
1829 % o exception: return any errors or warnings in this structure.
1833 static inline MagickBooleanType ValidatePixelCacheMorphology(
1834 const Image *restrict image)
1837 *restrict cache_info;
1839 const PixelChannelMap
1844 Does the image match the pixel cache morphology?
1846 cache_info=(CacheInfo *) image->cache;
1847 p=image->channel_map;
1848 q=cache_info->channel_map;
1849 if ((image->storage_class != cache_info->storage_class) ||
1850 (image->colorspace != cache_info->colorspace) ||
1851 (image->alpha_trait != cache_info->alpha_trait) ||
1852 (image->mask != cache_info->mask) ||
1853 (image->columns != cache_info->columns) ||
1854 (image->rows != cache_info->rows) ||
1855 (image->number_channels != cache_info->number_channels) ||
1856 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1857 (image->metacontent_extent != cache_info->metacontent_extent) ||
1858 (cache_info->nexus_info == (NexusInfo **) NULL))
1859 return(MagickFalse);
1863 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1864 ExceptionInfo *exception)
1873 static MagickSizeType
1879 cache_timestamp = 0;
1882 LockSemaphoreInfo(image->semaphore);
1883 if (cpu_throttle == 0)
1889 Set CPU throttle in milleseconds.
1891 cpu_throttle=MagickResourceInfinity;
1892 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1893 if (limit == (char *) NULL)
1894 limit=GetPolicyValue("throttle");
1895 if (limit != (char *) NULL)
1897 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1898 limit=DestroyString(limit);
1901 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1902 MagickDelay(cpu_throttle);
1903 if (time_limit == 0)
1906 Set the expire time in seconds.
1908 time_limit=GetMagickResourceLimit(TimeResource);
1909 cache_timestamp=time((time_t *) NULL);
1911 if ((time_limit != MagickResourceInfinity) &&
1912 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1913 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1914 assert(image->cache != (Cache) NULL);
1915 cache_info=(CacheInfo *) image->cache;
1916 destroy=MagickFalse;
1917 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1919 LockSemaphoreInfo(cache_info->semaphore);
1920 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1931 clone_image=(*image);
1932 clone_image.semaphore=AllocateSemaphoreInfo();
1933 clone_image.reference_count=1;
1934 clone_image.cache=ClonePixelCache(cache_info);
1935 clone_info=(CacheInfo *) clone_image.cache;
1936 status=OpenPixelCache(&clone_image,IOMode,exception);
1937 if (status != MagickFalse)
1939 if (clone != MagickFalse)
1940 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1941 if (status != MagickFalse)
1943 if (cache_info->mode == ReadMode)
1944 cache_info->nexus_info=(NexusInfo **) NULL;
1946 image->cache=clone_image.cache;
1949 DestroySemaphoreInfo(&clone_image.semaphore);
1951 UnlockSemaphoreInfo(cache_info->semaphore);
1953 if (destroy != MagickFalse)
1954 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1955 if (status != MagickFalse)
1958 Ensure the image matches the pixel cache morphology.
1960 image->taint=MagickTrue;
1961 image->type=UndefinedType;
1962 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1964 status=OpenPixelCache(image,IOMode,exception);
1965 cache_info=(CacheInfo *) image->cache;
1966 if (cache_info->type == DiskCache)
1967 (void) ClosePixelCacheOnDisk(cache_info);
1970 UnlockSemaphoreInfo(image->semaphore);
1971 if (status == MagickFalse)
1972 return((Cache) NULL);
1973 return(image->cache);
1977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1981 + G e t I m a g e P i x e l C a c h e T y p e %
1985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1987 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1988 % DiskCache, MemoryCache, MapCache, or PingCache.
1990 % The format of the GetImagePixelCacheType() method is:
1992 % CacheType GetImagePixelCacheType(const Image *image)
1994 % A description of each parameter follows:
1996 % o image: the image.
1999 MagickExport CacheType GetImagePixelCacheType(const Image *image)
2004 assert(image != (Image *) NULL);
2005 assert(image->signature == MagickSignature);
2006 assert(image->cache != (Cache) NULL);
2007 cache_info=(CacheInfo *) image->cache;
2008 assert(cache_info->signature == MagickSignature);
2009 return(cache_info->type);
2013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2017 % G e t O n e A u t h e n t i c P i x e l %
2021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2023 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2024 % location. The image background color is returned if an error occurs.
2026 % The format of the GetOneAuthenticPixel() method is:
2028 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2029 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2031 % A description of each parameter follows:
2033 % o image: the image.
2035 % o x,y: These values define the location of the pixel to return.
2037 % o pixel: return a pixel at the specified (x,y) location.
2039 % o exception: return any errors or warnings in this structure.
2042 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2043 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2054 assert(image != (Image *) NULL);
2055 assert(image->signature == MagickSignature);
2056 assert(image->cache != (Cache) NULL);
2057 cache_info=(CacheInfo *) image->cache;
2058 assert(cache_info->signature == MagickSignature);
2059 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2060 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2061 (GetOneAuthenticPixelFromHandler) NULL)
2062 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2064 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2065 if (q == (Quantum *) NULL)
2067 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2068 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2069 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2070 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2071 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2072 return(MagickFalse);
2074 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2079 channel=GetPixelChannelChannel(image,i);
2080 pixel[channel]=q[i];
2086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2090 + 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 %
2094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2096 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2097 % location. The image background color is returned if an error occurs.
2099 % The format of the GetOneAuthenticPixelFromCache() method is:
2101 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2102 % const ssize_t x,const ssize_t y,Quantum *pixel,
2103 % ExceptionInfo *exception)
2105 % A description of each parameter follows:
2107 % o image: the image.
2109 % o x,y: These values define the location of the pixel to return.
2111 % o pixel: return a pixel at the specified (x,y) location.
2113 % o exception: return any errors or warnings in this structure.
2116 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2117 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2123 id = GetOpenMPThreadId();
2131 assert(image != (const Image *) NULL);
2132 assert(image->signature == MagickSignature);
2133 assert(image->cache != (Cache) NULL);
2134 cache_info=(CacheInfo *) image->cache;
2135 assert(cache_info->signature == MagickSignature);
2136 assert(id < (int) cache_info->number_threads);
2137 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2138 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2140 if (q == (Quantum *) NULL)
2142 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2143 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2144 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2145 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2146 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2147 return(MagickFalse);
2149 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2154 channel=GetPixelChannelChannel(image,i);
2155 pixel[channel]=q[i];
2161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2165 % G e t O n e V i r t u a l P i x e l %
2169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2171 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2172 % (x,y) location. The image background color is returned if an error occurs.
2173 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2175 % The format of the GetOneVirtualPixel() method is:
2177 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2178 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2180 % A description of each parameter follows:
2182 % o image: the image.
2184 % o x,y: These values define the location of the pixel to return.
2186 % o pixel: return a pixel at the specified (x,y) location.
2188 % o exception: return any errors or warnings in this structure.
2191 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2192 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2198 id = GetOpenMPThreadId();
2206 assert(image != (const Image *) NULL);
2207 assert(image->signature == MagickSignature);
2208 assert(image->cache != (Cache) NULL);
2209 cache_info=(CacheInfo *) image->cache;
2210 assert(cache_info->signature == MagickSignature);
2211 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2212 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2213 (GetOneVirtualPixelFromHandler) NULL)
2214 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2215 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2216 assert(id < (int) cache_info->number_threads);
2217 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2218 1UL,1UL,cache_info->nexus_info[id],exception);
2219 if (p == (const Quantum *) NULL)
2221 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2222 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2223 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2224 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2225 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2226 return(MagickFalse);
2228 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2233 channel=GetPixelChannelChannel(image,i);
2234 pixel[channel]=p[i];
2240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2244 + 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 %
2248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2250 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2251 % specified (x,y) location. The image background color is returned if an
2254 % The format of the GetOneVirtualPixelFromCache() method is:
2256 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2257 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2258 % Quantum *pixel,ExceptionInfo *exception)
2260 % A description of each parameter follows:
2262 % o image: the image.
2264 % o virtual_pixel_method: the virtual pixel method.
2266 % o x,y: These values define the location of the pixel to return.
2268 % o pixel: return a pixel at the specified (x,y) location.
2270 % o exception: return any errors or warnings in this structure.
2273 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2274 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2275 Quantum *pixel,ExceptionInfo *exception)
2281 id = GetOpenMPThreadId();
2289 assert(image != (const Image *) NULL);
2290 assert(image->signature == MagickSignature);
2291 assert(image->cache != (Cache) NULL);
2292 cache_info=(CacheInfo *) image->cache;
2293 assert(cache_info->signature == MagickSignature);
2294 assert(id < (int) cache_info->number_threads);
2295 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2296 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2297 cache_info->nexus_info[id],exception);
2298 if (p == (const Quantum *) NULL)
2300 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2301 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2302 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2303 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2304 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2305 return(MagickFalse);
2307 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2312 channel=GetPixelChannelChannel(image,i);
2313 pixel[channel]=p[i];
2319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2323 % G e t O n e V i r t u a l P i x e l I n f o %
2327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2329 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2330 % location. The image background color is returned if an error occurs. If
2331 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2333 % The format of the GetOneVirtualPixelInfo() method is:
2335 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2336 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2337 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2339 % A description of each parameter follows:
2341 % o image: the image.
2343 % o virtual_pixel_method: the virtual pixel method.
2345 % o x,y: these values define the location of the pixel to return.
2347 % o pixel: return a pixel at the specified (x,y) location.
2349 % o exception: return any errors or warnings in this structure.
2352 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2353 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2354 PixelInfo *pixel,ExceptionInfo *exception)
2360 id = GetOpenMPThreadId();
2362 register const Quantum
2365 assert(image != (const Image *) NULL);
2366 assert(image->signature == MagickSignature);
2367 assert(image->cache != (Cache) NULL);
2368 cache_info=(CacheInfo *) image->cache;
2369 assert(cache_info->signature == MagickSignature);
2370 assert(id < (int) cache_info->number_threads);
2371 GetPixelInfo(image,pixel);
2372 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2373 cache_info->nexus_info[id],exception);
2374 if (p == (const Quantum *) NULL)
2375 return(MagickFalse);
2376 GetPixelInfoPixel(image,p,pixel);
2381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2385 + G e t P i x e l C a c h e C o l o r s p a c e %
2389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2391 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2393 % The format of the GetPixelCacheColorspace() method is:
2395 % Colorspace GetPixelCacheColorspace(Cache cache)
2397 % A description of each parameter follows:
2399 % o cache: the pixel cache.
2402 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2407 assert(cache != (Cache) NULL);
2408 cache_info=(CacheInfo *) cache;
2409 assert(cache_info->signature == MagickSignature);
2410 if (cache_info->debug != MagickFalse)
2411 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2412 cache_info->filename);
2413 return(cache_info->colorspace);
2417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2421 + G e t P i x e l C a c h e M e t h o d s %
2425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2427 % GetPixelCacheMethods() initializes the CacheMethods structure.
2429 % The format of the GetPixelCacheMethods() method is:
2431 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2433 % A description of each parameter follows:
2435 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2438 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2440 assert(cache_methods != (CacheMethods *) NULL);
2441 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2442 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2443 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2444 cache_methods->get_virtual_metacontent_from_handler=
2445 GetVirtualMetacontentFromCache;
2446 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2447 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2448 cache_methods->get_authentic_metacontent_from_handler=
2449 GetAuthenticMetacontentFromCache;
2450 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2451 cache_methods->get_one_authentic_pixel_from_handler=
2452 GetOneAuthenticPixelFromCache;
2453 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2454 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2455 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2463 + G e t P i x e l C a c h e N e x u s E x t e n t %
2467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2469 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2470 % corresponding with the last call to SetPixelCacheNexusPixels() or
2471 % GetPixelCacheNexusPixels().
2473 % The format of the GetPixelCacheNexusExtent() method is:
2475 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2476 % NexusInfo *nexus_info)
2478 % A description of each parameter follows:
2480 % o nexus_info: the nexus info.
2483 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2484 NexusInfo *nexus_info)
2492 assert(cache != NULL);
2493 cache_info=(CacheInfo *) cache;
2494 assert(cache_info->signature == MagickSignature);
2495 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2497 return((MagickSizeType) cache_info->columns*cache_info->rows);
2502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2506 + 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 %
2510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2512 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2515 % The format of the GetPixelCacheNexusMetacontent() method is:
2517 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2518 % NexusInfo *nexus_info)
2520 % A description of each parameter follows:
2522 % o cache: the pixel cache.
2524 % o nexus_info: the cache nexus to return the meta-content.
2527 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2528 NexusInfo *nexus_info)
2533 assert(cache != NULL);
2534 cache_info=(CacheInfo *) cache;
2535 assert(cache_info->signature == MagickSignature);
2536 if (cache_info->storage_class == UndefinedClass)
2537 return((void *) NULL);
2538 return(nexus_info->metacontent);
2542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2546 + G e t P i x e l C a c h e N e x u s P i x e l s %
2550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2552 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2555 % The format of the GetPixelCacheNexusPixels() method is:
2557 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2558 % NexusInfo *nexus_info)
2560 % A description of each parameter follows:
2562 % o cache: the pixel cache.
2564 % o nexus_info: the cache nexus to return the pixels.
2567 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2568 NexusInfo *nexus_info)
2573 assert(cache != NULL);
2574 cache_info=(CacheInfo *) cache;
2575 assert(cache_info->signature == MagickSignature);
2576 if (cache_info->storage_class == UndefinedClass)
2577 return((Quantum *) NULL);
2578 return(nexus_info->pixels);
2582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2586 + G e t P i x e l C a c h e P i x e l s %
2590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2592 % GetPixelCachePixels() returns the pixels associated with the specified image.
2594 % The format of the GetPixelCachePixels() method is:
2596 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2597 % ExceptionInfo *exception)
2599 % A description of each parameter follows:
2601 % o image: the image.
2603 % o length: the pixel cache length.
2605 % o exception: return any errors or warnings in this structure.
2608 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2609 ExceptionInfo *exception)
2614 assert(image != (const Image *) NULL);
2615 assert(image->signature == MagickSignature);
2616 assert(image->cache != (Cache) NULL);
2617 assert(length != (MagickSizeType *) NULL);
2618 assert(exception != (ExceptionInfo *) NULL);
2619 assert(exception->signature == MagickSignature);
2620 cache_info=(CacheInfo *) image->cache;
2621 assert(cache_info->signature == MagickSignature);
2623 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2624 return((void *) NULL);
2625 *length=cache_info->length;
2626 return((void *) cache_info->pixels);
2630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2634 + 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 %
2638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2640 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2642 % The format of the GetPixelCacheStorageClass() method is:
2644 % ClassType GetPixelCacheStorageClass(Cache cache)
2646 % A description of each parameter follows:
2648 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2650 % o cache: the pixel cache.
2653 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2658 assert(cache != (Cache) NULL);
2659 cache_info=(CacheInfo *) cache;
2660 assert(cache_info->signature == MagickSignature);
2661 if (cache_info->debug != MagickFalse)
2662 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2663 cache_info->filename);
2664 return(cache_info->storage_class);
2668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2672 + G e t P i x e l C a c h e T i l e S i z e %
2676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2678 % GetPixelCacheTileSize() returns the pixel cache tile size.
2680 % The format of the GetPixelCacheTileSize() method is:
2682 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2685 % A description of each parameter follows:
2687 % o image: the image.
2689 % o width: the optimize cache tile width in pixels.
2691 % o height: the optimize cache tile height in pixels.
2694 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2700 assert(image != (Image *) NULL);
2701 assert(image->signature == MagickSignature);
2702 if (image->debug != MagickFalse)
2703 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2704 cache_info=(CacheInfo *) image->cache;
2705 assert(cache_info->signature == MagickSignature);
2706 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2707 if (GetImagePixelCacheType(image) == DiskCache)
2708 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2717 + 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 %
2721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2723 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2724 % pixel cache. A virtual pixel is any pixel access that is outside the
2725 % boundaries of the image cache.
2727 % The format of the GetPixelCacheVirtualMethod() method is:
2729 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2731 % A description of each parameter follows:
2733 % o image: the image.
2736 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2741 assert(image != (Image *) NULL);
2742 assert(image->signature == MagickSignature);
2743 assert(image->cache != (Cache) NULL);
2744 cache_info=(CacheInfo *) image->cache;
2745 assert(cache_info->signature == MagickSignature);
2746 return(cache_info->virtual_pixel_method);
2750 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2754 + 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 %
2758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2760 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2761 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2763 % The format of the GetVirtualMetacontentFromCache() method is:
2765 % void *GetVirtualMetacontentFromCache(const Image *image)
2767 % A description of each parameter follows:
2769 % o image: the image.
2772 static const void *GetVirtualMetacontentFromCache(const Image *image)
2778 id = GetOpenMPThreadId();
2783 assert(image != (const Image *) NULL);
2784 assert(image->signature == MagickSignature);
2785 assert(image->cache != (Cache) NULL);
2786 cache_info=(CacheInfo *) image->cache;
2787 assert(cache_info->signature == MagickSignature);
2788 assert(id < (int) cache_info->number_threads);
2789 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2790 cache_info->nexus_info[id]);
2791 return(metacontent);
2795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2799 + 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 %
2803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2805 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2808 % The format of the GetVirtualMetacontentFromNexus() method is:
2810 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2811 % NexusInfo *nexus_info)
2813 % A description of each parameter follows:
2815 % o cache: the pixel cache.
2817 % o nexus_info: the cache nexus to return the meta-content.
2820 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2821 NexusInfo *nexus_info)
2826 assert(cache != (Cache) NULL);
2827 cache_info=(CacheInfo *) cache;
2828 assert(cache_info->signature == MagickSignature);
2829 if (cache_info->storage_class == UndefinedClass)
2830 return((void *) NULL);
2831 return(nexus_info->metacontent);
2835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2839 % G e t V i r t u a l M e t a c o n t e n t %
2843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2845 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2846 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2847 % returned if the meta-content are not available.
2849 % The format of the GetVirtualMetacontent() method is:
2851 % const void *GetVirtualMetacontent(const Image *image)
2853 % A description of each parameter follows:
2855 % o image: the image.
2858 MagickExport const void *GetVirtualMetacontent(const Image *image)
2864 id = GetOpenMPThreadId();
2869 assert(image != (const Image *) NULL);
2870 assert(image->signature == MagickSignature);
2871 assert(image->cache != (Cache) NULL);
2872 cache_info=(CacheInfo *) image->cache;
2873 assert(cache_info->signature == MagickSignature);
2874 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2875 if (metacontent != (void *) NULL)
2876 return(metacontent);
2877 assert(id < (int) cache_info->number_threads);
2878 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2879 cache_info->nexus_info[id]);
2880 return(metacontent);
2884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2888 + 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 %
2892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2894 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2895 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2896 % is returned if the pixels are transferred, otherwise a NULL is returned.
2898 % The format of the GetVirtualPixelsFromNexus() method is:
2900 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2901 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2902 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2903 % ExceptionInfo *exception)
2905 % A description of each parameter follows:
2907 % o image: the image.
2909 % o virtual_pixel_method: the virtual pixel method.
2911 % o x,y,columns,rows: These values define the perimeter of a region of
2914 % o nexus_info: the cache nexus to acquire.
2916 % o exception: return any errors or warnings in this structure.
2923 0, 48, 12, 60, 3, 51, 15, 63,
2924 32, 16, 44, 28, 35, 19, 47, 31,
2925 8, 56, 4, 52, 11, 59, 7, 55,
2926 40, 24, 36, 20, 43, 27, 39, 23,
2927 2, 50, 14, 62, 1, 49, 13, 61,
2928 34, 18, 46, 30, 33, 17, 45, 29,
2929 10, 58, 6, 54, 9, 57, 5, 53,
2930 42, 26, 38, 22, 41, 25, 37, 21
2933 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2938 index=x+DitherMatrix[x & 0x07]-32L;
2941 if (index >= (ssize_t) columns)
2942 return((ssize_t) columns-1L);
2946 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2951 index=y+DitherMatrix[y & 0x07]-32L;
2954 if (index >= (ssize_t) rows)
2955 return((ssize_t) rows-1L);
2959 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2963 if (x >= (ssize_t) columns)
2964 return((ssize_t) (columns-1));
2968 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2972 if (y >= (ssize_t) rows)
2973 return((ssize_t) (rows-1));
2977 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2979 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2982 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2984 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2987 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2988 const size_t extent)
2994 Compute the remainder of dividing offset by extent. It returns not only
2995 the quotient (tile the offset falls in) but also the positive remainer
2996 within that tile such that 0 <= remainder < extent. This method is
2997 essentially a ldiv() using a floored modulo division rather than the
2998 normal default truncated modulo division.
3000 modulo.quotient=offset/(ssize_t) extent;
3003 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3007 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3008 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3009 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3010 ExceptionInfo *exception)
3027 virtual_pixel[CompositePixelChannel];
3032 register const Quantum
3045 register unsigned char
3052 *virtual_metacontent;
3057 assert(image != (const Image *) NULL);
3058 assert(image->signature == MagickSignature);
3059 assert(image->cache != (Cache) NULL);
3060 cache_info=(CacheInfo *) image->cache;
3061 assert(cache_info->signature == MagickSignature);
3062 if (cache_info->type == UndefinedCache)
3063 return((const Quantum *) NULL);
3066 region.width=columns;
3068 pixels=SetPixelCacheNexusPixels(image,ReadMode,®ion,nexus_info,exception);
3069 if (pixels == (Quantum *) NULL)
3070 return((const Quantum *) NULL);
3072 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3073 nexus_info->region.x;
3074 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3075 nexus_info->region.width-1L;
3076 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3077 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3078 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3079 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3085 Pixel request is inside cache extents.
3087 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3089 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3090 if (status == MagickFalse)
3091 return((const Quantum *) NULL);
3092 if (cache_info->metacontent_extent != 0)
3094 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3095 if (status == MagickFalse)
3096 return((const Quantum *) NULL);
3101 Pixel request is outside cache extents.
3103 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3104 virtual_nexus=AcquirePixelCacheNexus(1);
3105 if (virtual_nexus == (NexusInfo **) NULL)
3107 if (virtual_nexus != (NexusInfo **) NULL)
3108 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3109 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3110 "UnableToGetCacheNexus","'%s'",image->filename);
3111 return((const Quantum *) NULL);
3113 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3114 sizeof(*virtual_pixel));
3115 virtual_metacontent=(void *) NULL;
3116 switch (virtual_pixel_method)
3118 case BackgroundVirtualPixelMethod:
3119 case BlackVirtualPixelMethod:
3120 case GrayVirtualPixelMethod:
3121 case TransparentVirtualPixelMethod:
3122 case MaskVirtualPixelMethod:
3123 case WhiteVirtualPixelMethod:
3124 case EdgeVirtualPixelMethod:
3125 case CheckerTileVirtualPixelMethod:
3126 case HorizontalTileVirtualPixelMethod:
3127 case VerticalTileVirtualPixelMethod:
3129 if (cache_info->metacontent_extent != 0)
3132 Acquire a metacontent buffer.
3134 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3135 cache_info->metacontent_extent);
3136 if (virtual_metacontent == (void *) NULL)
3138 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3139 (void) ThrowMagickException(exception,GetMagickModule(),
3140 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
3141 return((const Quantum *) NULL);
3143 (void) ResetMagickMemory(virtual_metacontent,0,
3144 cache_info->metacontent_extent);
3146 switch (virtual_pixel_method)
3148 case BlackVirtualPixelMethod:
3150 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3151 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3152 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3155 case GrayVirtualPixelMethod:
3157 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3158 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3160 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3163 case TransparentVirtualPixelMethod:
3165 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3166 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3167 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3170 case MaskVirtualPixelMethod:
3171 case WhiteVirtualPixelMethod:
3173 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3174 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3175 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3180 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3182 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3184 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3186 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3188 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3198 for (v=0; v < (ssize_t) rows; v++)
3200 for (u=0; u < (ssize_t) columns; u+=length)
3202 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3203 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3204 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3212 Transfer a single pixel.
3214 length=(MagickSizeType) 1;
3215 switch (virtual_pixel_method)
3219 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3220 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3221 1UL,1UL,*virtual_nexus,exception);
3222 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3225 case RandomVirtualPixelMethod:
3227 if (cache_info->random_info == (RandomInfo *) NULL)
3228 cache_info->random_info=AcquireRandomInfo();
3229 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3230 RandomX(cache_info->random_info,cache_info->columns),
3231 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3232 *virtual_nexus,exception);
3233 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3236 case DitherVirtualPixelMethod:
3238 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3239 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3240 1UL,1UL,*virtual_nexus,exception);
3241 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3244 case TileVirtualPixelMethod:
3246 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3247 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3248 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3249 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3251 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3254 case MirrorVirtualPixelMethod:
3256 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3257 if ((x_modulo.quotient & 0x01) == 1L)
3258 x_modulo.remainder=(ssize_t) cache_info->columns-
3259 x_modulo.remainder-1L;
3260 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3261 if ((y_modulo.quotient & 0x01) == 1L)
3262 y_modulo.remainder=(ssize_t) cache_info->rows-
3263 y_modulo.remainder-1L;
3264 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3265 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3267 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3270 case HorizontalTileEdgeVirtualPixelMethod:
3272 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3273 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3274 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3275 *virtual_nexus,exception);
3276 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3279 case VerticalTileEdgeVirtualPixelMethod:
3281 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3282 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3283 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3284 *virtual_nexus,exception);
3285 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3288 case BackgroundVirtualPixelMethod:
3289 case BlackVirtualPixelMethod:
3290 case GrayVirtualPixelMethod:
3291 case TransparentVirtualPixelMethod:
3292 case MaskVirtualPixelMethod:
3293 case WhiteVirtualPixelMethod:
3296 r=virtual_metacontent;
3299 case EdgeVirtualPixelMethod:
3300 case CheckerTileVirtualPixelMethod:
3302 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3303 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3304 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3307 r=virtual_metacontent;
3310 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3311 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3313 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3316 case HorizontalTileVirtualPixelMethod:
3318 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3321 r=virtual_metacontent;
3324 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3325 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3326 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3327 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3329 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3332 case VerticalTileVirtualPixelMethod:
3334 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3337 r=virtual_metacontent;
3340 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3341 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3342 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3343 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3345 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3349 if (p == (const Quantum *) NULL)
3351 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3353 q+=cache_info->number_channels;
3354 if ((s != (void *) NULL) && (r != (const void *) NULL))
3356 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3357 s+=cache_info->metacontent_extent;
3362 Transfer a run of pixels.
3364 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3365 length,1UL,*virtual_nexus,exception);
3366 if (p == (const Quantum *) NULL)
3368 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3369 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3370 q+=length*cache_info->number_channels;
3371 if ((r != (void *) NULL) && (s != (const void *) NULL))
3373 (void) memcpy(s,r,(size_t) length);
3374 s+=length*cache_info->metacontent_extent;
3381 if (virtual_metacontent != (void *) NULL)
3382 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3383 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3392 + G e t V i r t u a l P i x e l C a c h e %
3396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3398 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3399 % cache as defined by the geometry parameters. A pointer to the pixels
3400 % is returned if the pixels are transferred, otherwise a NULL is returned.
3402 % The format of the GetVirtualPixelCache() method is:
3404 % const Quantum *GetVirtualPixelCache(const Image *image,
3405 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3406 % const ssize_t y,const size_t columns,const size_t rows,
3407 % ExceptionInfo *exception)
3409 % A description of each parameter follows:
3411 % o image: the image.
3413 % o virtual_pixel_method: the virtual pixel method.
3415 % o x,y,columns,rows: These values define the perimeter of a region of
3418 % o exception: return any errors or warnings in this structure.
3421 static const Quantum *GetVirtualPixelCache(const Image *image,
3422 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3423 const size_t columns,const size_t rows,ExceptionInfo *exception)
3429 id = GetOpenMPThreadId();
3434 assert(image != (const Image *) NULL);
3435 assert(image->signature == MagickSignature);
3436 assert(image->cache != (Cache) NULL);
3437 cache_info=(CacheInfo *) image->cache;
3438 assert(cache_info->signature == MagickSignature);
3439 assert(id < (int) cache_info->number_threads);
3440 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3441 cache_info->nexus_info[id],exception);
3446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3450 % G e t V i r t u a l P i x e l Q u e u e %
3454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3456 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3457 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3459 % The format of the GetVirtualPixelQueue() method is:
3461 % const Quantum *GetVirtualPixelQueue(const Image image)
3463 % A description of each parameter follows:
3465 % o image: the image.
3468 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3474 id = GetOpenMPThreadId();
3476 assert(image != (const Image *) NULL);
3477 assert(image->signature == MagickSignature);
3478 assert(image->cache != (Cache) NULL);
3479 cache_info=(CacheInfo *) image->cache;
3480 assert(cache_info->signature == MagickSignature);
3481 if (cache_info->methods.get_virtual_pixels_handler !=
3482 (GetVirtualPixelsHandler) NULL)
3483 return(cache_info->methods.get_virtual_pixels_handler(image));
3484 assert(id < (int) cache_info->number_threads);
3485 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3493 % G e t V i r t u a l P i x e l s %
3497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3499 % GetVirtualPixels() returns an immutable pixel region. If the
3500 % region is successfully accessed, a pointer to it is returned, otherwise
3501 % NULL is returned. The returned pointer may point to a temporary working
3502 % copy of the pixels or it may point to the original pixels in memory.
3503 % Performance is maximized if the selected region is part of one row, or one
3504 % or more full rows, since there is opportunity to access the pixels in-place
3505 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3506 % returned pointer must *never* be deallocated by the user.
3508 % Pixels accessed via the returned pointer represent a simple array of type
3509 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3510 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3511 % access the meta-content (of type void) corresponding to the the
3514 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3516 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3517 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3518 % GetCacheViewAuthenticPixels() instead.
3520 % The format of the GetVirtualPixels() method is:
3522 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3523 % const ssize_t y,const size_t columns,const size_t rows,
3524 % ExceptionInfo *exception)
3526 % A description of each parameter follows:
3528 % o image: the image.
3530 % o x,y,columns,rows: These values define the perimeter of a region of
3533 % o exception: return any errors or warnings in this structure.
3536 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3537 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3538 ExceptionInfo *exception)
3544 id = GetOpenMPThreadId();
3549 assert(image != (const Image *) NULL);
3550 assert(image->signature == MagickSignature);
3551 assert(image->cache != (Cache) NULL);
3552 cache_info=(CacheInfo *) image->cache;
3553 assert(cache_info->signature == MagickSignature);
3554 if (cache_info->methods.get_virtual_pixel_handler !=
3555 (GetVirtualPixelHandler) NULL)
3556 return(cache_info->methods.get_virtual_pixel_handler(image,
3557 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3558 assert(id < (int) cache_info->number_threads);
3559 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3560 columns,rows,cache_info->nexus_info[id],exception);
3565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3569 + 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 %
3573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3575 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3576 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3578 % The format of the GetVirtualPixelsCache() method is:
3580 % Quantum *GetVirtualPixelsCache(const Image *image)
3582 % A description of each parameter follows:
3584 % o image: the image.
3587 static const Quantum *GetVirtualPixelsCache(const Image *image)
3593 id = GetOpenMPThreadId();
3595 assert(image != (const Image *) NULL);
3596 assert(image->signature == MagickSignature);
3597 assert(image->cache != (Cache) NULL);
3598 cache_info=(CacheInfo *) image->cache;
3599 assert(cache_info->signature == MagickSignature);
3600 assert(id < (int) cache_info->number_threads);
3601 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3609 + G e t V i r t u a l P i x e l s N e x u s %
3613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3615 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3618 % The format of the GetVirtualPixelsNexus() method is:
3620 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3621 % NexusInfo *nexus_info)
3623 % A description of each parameter follows:
3625 % o cache: the pixel cache.
3627 % o nexus_info: the cache nexus to return the colormap pixels.
3630 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3631 NexusInfo *nexus_info)
3636 assert(cache != (Cache) NULL);
3637 cache_info=(CacheInfo *) cache;
3638 assert(cache_info->signature == MagickSignature);
3639 if (cache_info->storage_class == UndefinedClass)
3640 return((Quantum *) NULL);
3641 return((const Quantum *) nexus_info->pixels);
3645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3649 + O p e n P i x e l C a c h e %
3653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3655 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3656 % dimensions, allocating space for the image pixels and optionally the
3657 % metacontent, and memory mapping the cache if it is disk based. The cache
3658 % nexus array is initialized as well.
3660 % The format of the OpenPixelCache() method is:
3662 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3663 % ExceptionInfo *exception)
3665 % A description of each parameter follows:
3667 % o image: the image.
3669 % o mode: ReadMode, WriteMode, or IOMode.
3671 % o exception: return any errors or warnings in this structure.
3675 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3677 cache_info->mapped=MagickFalse;
3678 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3679 (size_t) cache_info->length));
3680 if (cache_info->pixels == (Quantum *) NULL)
3682 cache_info->mapped=MagickTrue;
3683 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3684 cache_info->length);
3688 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3697 cache_info=(CacheInfo *) image->cache;
3698 if (image->debug != MagickFalse)
3701 format[MaxTextExtent],
3702 message[MaxTextExtent];
3704 (void) FormatMagickSize(length,MagickFalse,format);
3705 (void) FormatLocaleString(message,MaxTextExtent,
3706 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3707 cache_info->cache_filename,cache_info->file,format);
3708 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3710 if (length != (MagickSizeType) ((MagickOffsetType) length))
3711 return(MagickFalse);
3712 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3714 return(MagickFalse);
3715 if ((MagickSizeType) offset >= length)
3717 extent=(MagickOffsetType) length-1;
3718 #if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3723 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3724 if (count != (MagickOffsetType) 1)
3725 return(MagickFalse);
3732 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3734 return(MagickFalse);
3740 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3741 ExceptionInfo *exception)
3748 format[MaxTextExtent],
3749 message[MaxTextExtent];
3762 assert(image != (const Image *) NULL);
3763 assert(image->signature == MagickSignature);
3764 assert(image->cache != (Cache) NULL);
3765 if (image->debug != MagickFalse)
3766 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3767 if ((image->columns == 0) || (image->rows == 0))
3768 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3769 cache_info=(CacheInfo *) image->cache;
3770 assert(cache_info->signature == MagickSignature);
3771 source_info=(*cache_info);
3772 source_info.file=(-1);
3773 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3774 image->filename,(double) GetImageIndexInList(image));
3775 cache_info->storage_class=image->storage_class;
3776 cache_info->colorspace=image->colorspace;
3777 cache_info->alpha_trait=image->alpha_trait;
3778 cache_info->mask=image->mask;
3779 cache_info->rows=image->rows;
3780 cache_info->columns=image->columns;
3781 InitializePixelChannelMap(image);
3782 cache_info->number_channels=GetPixelChannels(image);
3783 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3784 sizeof(*image->channel_map));
3785 cache_info->metacontent_extent=image->metacontent_extent;
3786 cache_info->mode=mode;
3787 if (image->ping != MagickFalse)
3789 cache_info->type=PingCache;
3790 cache_info->pixels=(Quantum *) NULL;
3791 cache_info->metacontent=(void *) NULL;
3792 cache_info->length=0;
3795 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3796 packet_size=cache_info->number_channels*sizeof(Quantum);
3797 if (image->metacontent_extent != 0)
3798 packet_size+=cache_info->metacontent_extent;
3799 length=number_pixels*packet_size;
3800 columns=(size_t) (length/cache_info->rows/packet_size);
3801 if (cache_info->columns != columns)
3802 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3804 cache_info->length=length;
3805 status=AcquireMagickResource(AreaResource,cache_info->length);
3806 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3807 cache_info->metacontent_extent);
3808 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3810 status=AcquireMagickResource(MemoryResource,cache_info->length);
3811 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3812 (cache_info->type == MemoryCache))
3814 AllocatePixelCachePixels(cache_info);
3815 if (cache_info->pixels == (Quantum *) NULL)
3816 cache_info->pixels=source_info.pixels;
3820 Create memory pixel cache.
3823 if (image->debug != MagickFalse)
3825 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3826 (void) FormatLocaleString(message,MaxTextExtent,
3827 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3828 cache_info->filename,cache_info->mapped != MagickFalse ?
3829 "anonymous" : "heap",(double) cache_info->columns,(double)
3830 cache_info->rows,(double) cache_info->number_channels,
3832 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3835 cache_info->type=MemoryCache;
3836 cache_info->metacontent=(void *) NULL;
3837 if (cache_info->metacontent_extent != 0)
3838 cache_info->metacontent=(void *) (cache_info->pixels+
3839 number_pixels*cache_info->number_channels);
3840 if ((source_info.storage_class != UndefinedClass) &&
3843 status=ClonePixelCachePixels(cache_info,&source_info,
3845 RelinquishPixelCachePixels(&source_info);
3850 RelinquishMagickResource(MemoryResource,cache_info->length);
3853 Create pixel cache on disk.
3855 status=AcquireMagickResource(DiskResource,cache_info->length);
3856 if (status == MagickFalse)
3858 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3859 "CacheResourcesExhausted","'%s'",image->filename);
3860 return(MagickFalse);
3862 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3864 (void) ClosePixelCacheOnDisk(cache_info);
3865 *cache_info->cache_filename='\0';
3867 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3869 RelinquishMagickResource(DiskResource,cache_info->length);
3870 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3872 return(MagickFalse);
3874 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3875 cache_info->length);
3876 if (status == MagickFalse)
3878 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3880 return(MagickFalse);
3882 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3883 cache_info->metacontent_extent);
3884 if (length != (MagickSizeType) ((size_t) length))
3885 cache_info->type=DiskCache;
3888 status=AcquireMagickResource(MapResource,cache_info->length);
3889 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3890 (cache_info->type != MemoryCache))
3891 cache_info->type=DiskCache;
3894 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3895 cache_info->offset,(size_t) cache_info->length);
3896 if (cache_info->pixels == (Quantum *) NULL)
3898 cache_info->type=DiskCache;
3899 cache_info->pixels=source_info.pixels;
3904 Create file-backed memory-mapped pixel cache.
3907 (void) ClosePixelCacheOnDisk(cache_info);
3908 cache_info->type=MapCache;
3909 cache_info->mapped=MagickTrue;
3910 cache_info->metacontent=(void *) NULL;
3911 if (cache_info->metacontent_extent != 0)
3912 cache_info->metacontent=(void *) (cache_info->pixels+
3913 number_pixels*cache_info->number_channels);
3914 if ((source_info.storage_class != UndefinedClass) &&
3917 status=ClonePixelCachePixels(cache_info,&source_info,
3919 RelinquishPixelCachePixels(&source_info);
3921 if (image->debug != MagickFalse)
3923 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3924 (void) FormatLocaleString(message,MaxTextExtent,
3925 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
3926 cache_info->filename,cache_info->cache_filename,
3927 cache_info->file,(double) cache_info->columns,(double)
3928 cache_info->rows,(double) cache_info->number_channels,
3930 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3936 RelinquishMagickResource(MapResource,cache_info->length);
3939 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3941 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3942 RelinquishPixelCachePixels(&source_info);
3944 if (image->debug != MagickFalse)
3946 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3947 (void) FormatLocaleString(message,MaxTextExtent,
3948 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
3949 cache_info->cache_filename,cache_info->file,(double)
3950 cache_info->columns,(double) cache_info->rows,(double)
3951 cache_info->number_channels,format);
3952 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3962 + P e r s i s t P i x e l C a c h e %
3966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3968 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3969 % persistent pixel cache is one that resides on disk and is not destroyed
3970 % when the program exits.
3972 % The format of the PersistPixelCache() method is:
3974 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3975 % const MagickBooleanType attach,MagickOffsetType *offset,
3976 % ExceptionInfo *exception)
3978 % A description of each parameter follows:
3980 % o image: the image.
3982 % o filename: the persistent pixel cache filename.
3984 % o attach: A value other than zero initializes the persistent pixel cache.
3986 % o initialize: A value other than zero initializes the persistent pixel
3989 % o offset: the offset in the persistent cache to store pixels.
3991 % o exception: return any errors or warnings in this structure.
3994 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3995 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3996 ExceptionInfo *exception)
4011 assert(image != (Image *) NULL);
4012 assert(image->signature == MagickSignature);
4013 if (image->debug != MagickFalse)
4014 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4015 assert(image->cache != (void *) NULL);
4016 assert(filename != (const char *) NULL);
4017 assert(offset != (MagickOffsetType *) NULL);
4018 page_size=GetMagickPageSize();
4019 cache_info=(CacheInfo *) image->cache;
4020 assert(cache_info->signature == MagickSignature);
4021 if (attach != MagickFalse)
4024 Attach existing persistent pixel cache.
4026 if (image->debug != MagickFalse)
4027 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4028 "attach persistent cache");
4029 (void) CopyMagickString(cache_info->cache_filename,filename,
4031 cache_info->type=DiskCache;
4032 cache_info->offset=(*offset);
4033 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4034 return(MagickFalse);
4035 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4038 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4039 (cache_info->reference_count == 1))
4041 LockSemaphoreInfo(cache_info->semaphore);
4042 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4043 (cache_info->reference_count == 1))
4049 Usurp existing persistent pixel cache.
4051 status=rename_utf8(cache_info->cache_filename,filename);
4054 (void) CopyMagickString(cache_info->cache_filename,filename,
4056 *offset+=cache_info->length+page_size-(cache_info->length %
4058 UnlockSemaphoreInfo(cache_info->semaphore);
4059 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4060 if (image->debug != MagickFalse)
4061 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4062 "Usurp resident persistent cache");
4066 UnlockSemaphoreInfo(cache_info->semaphore);
4069 Clone persistent pixel cache.
4071 clone_image=(*image);
4072 clone_info=(CacheInfo *) clone_image.cache;
4073 image->cache=ClonePixelCache(cache_info);
4074 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4075 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4076 cache_info->type=DiskCache;
4077 cache_info->offset=(*offset);
4078 cache_info=(CacheInfo *) image->cache;
4079 status=OpenPixelCache(image,IOMode,exception);
4080 if (status != MagickFalse)
4081 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4082 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4083 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4092 + 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 %
4096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4098 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4099 % defined by the region rectangle and returns a pointer to the region. This
4100 % region is subsequently transferred from the pixel cache with
4101 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4102 % pixels are transferred, otherwise a NULL is returned.
4104 % The format of the QueueAuthenticPixelCacheNexus() method is:
4106 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4107 % const ssize_t y,const size_t columns,const size_t rows,
4108 % const MagickBooleanType clone,NexusInfo *nexus_info,
4109 % ExceptionInfo *exception)
4111 % A description of each parameter follows:
4113 % o image: the image.
4115 % o x,y,columns,rows: These values define the perimeter of a region of
4118 % o nexus_info: the cache nexus to set.
4120 % o clone: clone the pixel cache.
4122 % o exception: return any errors or warnings in this structure.
4125 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4126 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4127 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4142 Validate pixel cache geometry.
4144 assert(image != (const Image *) NULL);
4145 assert(image->signature == MagickSignature);
4146 assert(image->cache != (Cache) NULL);
4147 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4148 if (cache_info == (Cache) NULL)
4149 return((Quantum *) NULL);
4150 assert(cache_info->signature == MagickSignature);
4151 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4153 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4154 "NoPixelsDefinedInCache","'%s'",image->filename);
4155 return((Quantum *) NULL);
4157 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4158 (y >= (ssize_t) cache_info->rows))
4160 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4161 "PixelsAreNotAuthentic","'%s'",image->filename);
4162 return((Quantum *) NULL);
4164 offset=(MagickOffsetType) y*cache_info->columns+x;
4166 return((Quantum *) NULL);
4167 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4168 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4169 if ((MagickSizeType) offset >= number_pixels)
4170 return((Quantum *) NULL);
4176 region.width=columns;
4178 return(SetPixelCacheNexusPixels(image,WriteMode,®ion,nexus_info,exception));
4182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4186 + 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 %
4190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4192 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4193 % defined by the region rectangle and returns a pointer to the region. This
4194 % region is subsequently transferred from the pixel cache with
4195 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4196 % pixels are transferred, otherwise a NULL is returned.
4198 % The format of the QueueAuthenticPixelsCache() method is:
4200 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4201 % const ssize_t y,const size_t columns,const size_t rows,
4202 % ExceptionInfo *exception)
4204 % A description of each parameter follows:
4206 % o image: the image.
4208 % o x,y,columns,rows: These values define the perimeter of a region of
4211 % o exception: return any errors or warnings in this structure.
4214 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4215 const ssize_t y,const size_t columns,const size_t rows,
4216 ExceptionInfo *exception)
4222 id = GetOpenMPThreadId();
4227 assert(image != (const Image *) NULL);
4228 assert(image->signature == MagickSignature);
4229 assert(image->cache != (Cache) NULL);
4230 cache_info=(CacheInfo *) image->cache;
4231 assert(cache_info->signature == MagickSignature);
4232 assert(id < (int) cache_info->number_threads);
4233 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4234 cache_info->nexus_info[id],exception);
4239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4243 % Q u e u e A u t h e n t i c P i x e l s %
4247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4249 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4250 % successfully initialized a pointer to a Quantum array representing the
4251 % region is returned, otherwise NULL is returned. The returned pointer may
4252 % point to a temporary working buffer for the pixels or it may point to the
4253 % final location of the pixels in memory.
4255 % Write-only access means that any existing pixel values corresponding to
4256 % the region are ignored. This is useful if the initial image is being
4257 % created from scratch, or if the existing pixel values are to be
4258 % completely replaced without need to refer to their pre-existing values.
4259 % The application is free to read and write the pixel buffer returned by
4260 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4261 % initialize the pixel array values. Initializing pixel array values is the
4262 % application's responsibility.
4264 % Performance is maximized if the selected region is part of one row, or
4265 % one or more full rows, since then there is opportunity to access the
4266 % pixels in-place (without a copy) if the image is in memory, or in a
4267 % memory-mapped file. The returned pointer must *never* be deallocated
4270 % Pixels accessed via the returned pointer represent a simple array of type
4271 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4272 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4273 % obtain the meta-content (of type void) corresponding to the region.
4274 % Once the Quantum (and/or Quantum) array has been updated, the
4275 % changes must be saved back to the underlying image using
4276 % SyncAuthenticPixels() or they may be lost.
4278 % The format of the QueueAuthenticPixels() method is:
4280 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4281 % const ssize_t y,const size_t columns,const size_t rows,
4282 % ExceptionInfo *exception)
4284 % A description of each parameter follows:
4286 % o image: the image.
4288 % o x,y,columns,rows: These values define the perimeter of a region of
4291 % o exception: return any errors or warnings in this structure.
4294 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4295 const ssize_t y,const size_t columns,const size_t rows,
4296 ExceptionInfo *exception)
4302 id = GetOpenMPThreadId();
4307 assert(image != (Image *) NULL);
4308 assert(image->signature == MagickSignature);
4309 assert(image->cache != (Cache) NULL);
4310 cache_info=(CacheInfo *) image->cache;
4311 assert(cache_info->signature == MagickSignature);
4312 if (cache_info->methods.queue_authentic_pixels_handler !=
4313 (QueueAuthenticPixelsHandler) NULL)
4315 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4319 assert(id < (int) cache_info->number_threads);
4320 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4321 cache_info->nexus_info[id],exception);
4326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4330 + 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 %
4334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4336 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4339 % The format of the ReadPixelCacheMetacontent() method is:
4341 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4342 % NexusInfo *nexus_info,ExceptionInfo *exception)
4344 % A description of each parameter follows:
4346 % o cache_info: the pixel cache.
4348 % o nexus_info: the cache nexus to read the metacontent.
4350 % o exception: return any errors or warnings in this structure.
4353 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4354 NexusInfo *nexus_info,ExceptionInfo *exception)
4367 register unsigned char
4373 if (cache_info->metacontent_extent == 0)
4374 return(MagickFalse);
4375 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4377 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4378 nexus_info->region.x;
4379 length=(MagickSizeType) nexus_info->region.width*
4380 cache_info->metacontent_extent;
4381 rows=nexus_info->region.height;
4383 q=(unsigned char *) nexus_info->metacontent;
4384 switch (cache_info->type)
4389 register unsigned char
4393 Read meta-content from memory.
4395 if ((cache_info->columns == nexus_info->region.width) &&
4396 (extent == (MagickSizeType) ((size_t) extent)))
4401 p=(unsigned char *) cache_info->metacontent+offset*
4402 cache_info->metacontent_extent;
4403 for (y=0; y < (ssize_t) rows; y++)
4405 (void) memcpy(q,p,(size_t) length);
4406 p+=cache_info->metacontent_extent*cache_info->columns;
4407 q+=cache_info->metacontent_extent*nexus_info->region.width;
4414 Read meta content from disk.
4416 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4418 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4419 cache_info->cache_filename);
4420 return(MagickFalse);
4422 if ((cache_info->columns == nexus_info->region.width) &&
4423 (extent <= MagickMaxBufferExtent))
4428 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4429 for (y=0; y < (ssize_t) rows; y++)
4431 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4432 cache_info->number_channels*sizeof(Quantum)+offset*
4433 cache_info->metacontent_extent,length,(unsigned char *) q);
4434 if ((MagickSizeType) count != length)
4436 offset+=cache_info->columns;
4437 q+=cache_info->metacontent_extent*nexus_info->region.width;
4439 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4440 (void) ClosePixelCacheOnDisk(cache_info);
4441 if (y < (ssize_t) rows)
4443 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4444 cache_info->cache_filename);
4445 return(MagickFalse);
4452 if ((cache_info->debug != MagickFalse) &&
4453 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4454 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4455 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4456 nexus_info->region.width,(double) nexus_info->region.height,(double)
4457 nexus_info->region.x,(double) nexus_info->region.y);
4462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4466 + R e a d P i x e l C a c h e P i x e l s %
4470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4472 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4475 % The format of the ReadPixelCachePixels() method is:
4477 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4478 % NexusInfo *nexus_info,ExceptionInfo *exception)
4480 % A description of each parameter follows:
4482 % o cache_info: the pixel cache.
4484 % o nexus_info: the cache nexus to read the pixels.
4486 % o exception: return any errors or warnings in this structure.
4489 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4490 NexusInfo *nexus_info,ExceptionInfo *exception)
4509 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4511 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4512 nexus_info->region.x;
4513 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4515 rows=nexus_info->region.height;
4517 q=nexus_info->pixels;
4518 switch (cache_info->type)
4527 Read pixels from memory.
4529 if ((cache_info->columns == nexus_info->region.width) &&
4530 (extent == (MagickSizeType) ((size_t) extent)))
4535 p=cache_info->pixels+offset*cache_info->number_channels;
4536 for (y=0; y < (ssize_t) rows; y++)
4538 (void) memcpy(q,p,(size_t) length);
4539 p+=cache_info->number_channels*cache_info->columns;
4540 q+=cache_info->number_channels*nexus_info->region.width;
4547 Read pixels from disk.
4549 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4551 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4552 cache_info->cache_filename);
4553 return(MagickFalse);
4555 if ((cache_info->columns == nexus_info->region.width) &&
4556 (extent <= MagickMaxBufferExtent))
4561 for (y=0; y < (ssize_t) rows; y++)
4563 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4564 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4565 if ((MagickSizeType) count != length)
4567 offset+=cache_info->columns;
4568 q+=cache_info->number_channels*nexus_info->region.width;
4570 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4571 (void) ClosePixelCacheOnDisk(cache_info);
4572 if (y < (ssize_t) rows)
4574 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4575 cache_info->cache_filename);
4576 return(MagickFalse);
4583 if ((cache_info->debug != MagickFalse) &&
4584 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4585 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4586 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4587 nexus_info->region.width,(double) nexus_info->region.height,(double)
4588 nexus_info->region.x,(double) nexus_info->region.y);
4593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4597 + R e f e r e n c e P i x e l C a c h e %
4601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4603 % ReferencePixelCache() increments the reference count associated with the
4604 % pixel cache returning a pointer to the cache.
4606 % The format of the ReferencePixelCache method is:
4608 % Cache ReferencePixelCache(Cache cache_info)
4610 % A description of each parameter follows:
4612 % o cache_info: the pixel cache.
4615 MagickPrivate Cache ReferencePixelCache(Cache cache)
4620 assert(cache != (Cache *) NULL);
4621 cache_info=(CacheInfo *) cache;
4622 assert(cache_info->signature == MagickSignature);
4623 LockSemaphoreInfo(cache_info->semaphore);
4624 cache_info->reference_count++;
4625 UnlockSemaphoreInfo(cache_info->semaphore);
4630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4634 + S e t P i x e l C a c h e M e t h o d s %
4638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4640 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4642 % The format of the SetPixelCacheMethods() method is:
4644 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4646 % A description of each parameter follows:
4648 % o cache: the pixel cache.
4650 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4653 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4658 GetOneAuthenticPixelFromHandler
4659 get_one_authentic_pixel_from_handler;
4661 GetOneVirtualPixelFromHandler
4662 get_one_virtual_pixel_from_handler;
4665 Set cache pixel methods.
4667 assert(cache != (Cache) NULL);
4668 assert(cache_methods != (CacheMethods *) NULL);
4669 cache_info=(CacheInfo *) cache;
4670 assert(cache_info->signature == MagickSignature);
4671 if (cache_info->debug != MagickFalse)
4672 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4673 cache_info->filename);
4674 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4675 cache_info->methods.get_virtual_pixel_handler=
4676 cache_methods->get_virtual_pixel_handler;
4677 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4678 cache_info->methods.destroy_pixel_handler=
4679 cache_methods->destroy_pixel_handler;
4680 if (cache_methods->get_virtual_metacontent_from_handler !=
4681 (GetVirtualMetacontentFromHandler) NULL)
4682 cache_info->methods.get_virtual_metacontent_from_handler=
4683 cache_methods->get_virtual_metacontent_from_handler;
4684 if (cache_methods->get_authentic_pixels_handler !=
4685 (GetAuthenticPixelsHandler) NULL)
4686 cache_info->methods.get_authentic_pixels_handler=
4687 cache_methods->get_authentic_pixels_handler;
4688 if (cache_methods->queue_authentic_pixels_handler !=
4689 (QueueAuthenticPixelsHandler) NULL)
4690 cache_info->methods.queue_authentic_pixels_handler=
4691 cache_methods->queue_authentic_pixels_handler;
4692 if (cache_methods->sync_authentic_pixels_handler !=
4693 (SyncAuthenticPixelsHandler) NULL)
4694 cache_info->methods.sync_authentic_pixels_handler=
4695 cache_methods->sync_authentic_pixels_handler;
4696 if (cache_methods->get_authentic_pixels_from_handler !=
4697 (GetAuthenticPixelsFromHandler) NULL)
4698 cache_info->methods.get_authentic_pixels_from_handler=
4699 cache_methods->get_authentic_pixels_from_handler;
4700 if (cache_methods->get_authentic_metacontent_from_handler !=
4701 (GetAuthenticMetacontentFromHandler) NULL)
4702 cache_info->methods.get_authentic_metacontent_from_handler=
4703 cache_methods->get_authentic_metacontent_from_handler;
4704 get_one_virtual_pixel_from_handler=
4705 cache_info->methods.get_one_virtual_pixel_from_handler;
4706 if (get_one_virtual_pixel_from_handler !=
4707 (GetOneVirtualPixelFromHandler) NULL)
4708 cache_info->methods.get_one_virtual_pixel_from_handler=
4709 cache_methods->get_one_virtual_pixel_from_handler;
4710 get_one_authentic_pixel_from_handler=
4711 cache_methods->get_one_authentic_pixel_from_handler;
4712 if (get_one_authentic_pixel_from_handler !=
4713 (GetOneAuthenticPixelFromHandler) NULL)
4714 cache_info->methods.get_one_authentic_pixel_from_handler=
4715 cache_methods->get_one_authentic_pixel_from_handler;
4719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4723 + S e t P i x e l C a c h e N e x u s P i x e l s %
4727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4729 % SetPixelCacheNexusPixels() defines the region of the cache for the
4730 % specified cache nexus.
4732 % The format of the SetPixelCacheNexusPixels() method is:
4734 % Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4735 % const RectangleInfo *region,NexusInfo *nexus_info,
4736 % ExceptionInfo *exception)
4738 % A description of each parameter follows:
4740 % o image: the image.
4742 % o mode: ReadMode, WriteMode, or IOMode.
4744 % o region: A pointer to the RectangleInfo structure that defines the
4745 % region of this particular cache nexus.
4747 % o nexus_info: the cache nexus to set.
4749 % o exception: return any errors or warnings in this structure.
4753 static inline MagickBooleanType AcquireCacheNexusPixels(
4754 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4755 ExceptionInfo *exception)
4757 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4758 return(MagickFalse);
4759 nexus_info->mapped=MagickFalse;
4760 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4761 (size_t) nexus_info->length));
4762 if (nexus_info->cache == (Quantum *) NULL)
4764 nexus_info->mapped=MagickTrue;
4765 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4766 nexus_info->length);
4768 if (nexus_info->cache == (Quantum *) NULL)
4770 (void) ThrowMagickException(exception,GetMagickModule(),
4771 ResourceLimitError,"MemoryAllocationFailed","'%s'",
4772 cache_info->filename);
4773 return(MagickFalse);
4778 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4781 if (mode == ReadMode)
4783 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4786 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4789 static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4790 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4802 cache_info=(CacheInfo *) image->cache;
4803 assert(cache_info->signature == MagickSignature);
4804 if (cache_info->type == UndefinedCache)
4805 return((Quantum *) NULL);
4806 nexus_info->region=(*region);
4807 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
4813 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4814 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4815 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4816 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4817 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4818 ((nexus_info->region.width == cache_info->columns) ||
4819 ((nexus_info->region.width % cache_info->columns) == 0)))))
4825 Pixels are accessed directly from memory.
4827 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4828 nexus_info->region.x;
4829 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4831 nexus_info->metacontent=(void *) NULL;
4832 if (cache_info->metacontent_extent != 0)
4833 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4834 offset*cache_info->metacontent_extent;
4835 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4836 return(nexus_info->pixels);
4840 Pixels are stored in a cache region until they are synced to the cache.
4842 number_pixels=(MagickSizeType) nexus_info->region.width*
4843 nexus_info->region.height;
4844 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4845 if (cache_info->metacontent_extent != 0)
4846 length+=number_pixels*cache_info->metacontent_extent;
4847 if (nexus_info->cache == (Quantum *) NULL)
4849 nexus_info->length=length;
4850 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4851 if (status == MagickFalse)
4853 nexus_info->length=0;
4854 return((Quantum *) NULL);
4858 if (nexus_info->length != length)
4860 RelinquishCacheNexusPixels(nexus_info);
4861 nexus_info->length=length;
4862 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4863 if (status == MagickFalse)
4865 nexus_info->length=0;
4866 return((Quantum *) NULL);
4869 nexus_info->pixels=nexus_info->cache;
4870 nexus_info->metacontent=(void *) NULL;
4871 if (cache_info->metacontent_extent != 0)
4872 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4873 cache_info->number_channels);
4874 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4875 return(nexus_info->pixels);
4879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4883 % 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 %
4887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4889 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4890 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4891 % access that is outside the boundaries of the image cache.
4893 % The format of the SetPixelCacheVirtualMethod() method is:
4895 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4896 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4898 % A description of each parameter follows:
4900 % o image: the image.
4902 % o virtual_pixel_method: choose the type of virtual pixel.
4904 % o exception: return any errors or warnings in this structure.
4908 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4909 ExceptionInfo *exception)
4923 assert(image != (Image *) NULL);
4924 assert(image->signature == MagickSignature);
4925 if (image->debug != MagickFalse)
4926 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4927 assert(image->cache != (Cache) NULL);
4928 cache_info=(CacheInfo *) image->cache;
4929 assert(cache_info->signature == MagickSignature);
4930 image->alpha_trait=BlendPixelTrait;
4932 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4933 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4934 #pragma omp parallel for schedule(static,4) shared(status) \
4935 dynamic_number_threads(image,image->columns,image->rows,1)
4937 for (y=0; y < (ssize_t) image->rows; y++)
4945 if (status == MagickFalse)
4947 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4948 if (q == (Quantum *) NULL)
4953 for (x=0; x < (ssize_t) image->columns; x++)
4955 SetPixelAlpha(image,alpha,q);
4956 q+=GetPixelChannels(image);
4958 status=SyncCacheViewAuthenticPixels(image_view,exception);
4960 image_view=DestroyCacheView(image_view);
4964 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4965 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4973 assert(image != (Image *) NULL);
4974 assert(image->signature == MagickSignature);
4975 if (image->debug != MagickFalse)
4976 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4977 assert(image->cache != (Cache) NULL);
4978 cache_info=(CacheInfo *) image->cache;
4979 assert(cache_info->signature == MagickSignature);
4980 method=cache_info->virtual_pixel_method;
4981 cache_info->virtual_pixel_method=virtual_pixel_method;
4982 if ((image->columns != 0) && (image->rows != 0))
4983 switch (virtual_pixel_method)
4985 case BackgroundVirtualPixelMethod:
4987 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4988 (image->alpha_trait != BlendPixelTrait))
4989 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4990 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4991 (IsGrayColorspace(image->colorspace) != MagickFalse))
4992 (void) TransformImageColorspace(image,RGBColorspace,exception);
4995 case TransparentVirtualPixelMethod:
4997 if (image->alpha_trait != BlendPixelTrait)
4998 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5012 + 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 %
5016 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5018 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5019 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5020 % is synced, otherwise MagickFalse.
5022 % The format of the SyncAuthenticPixelCacheNexus() method is:
5024 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5025 % NexusInfo *nexus_info,ExceptionInfo *exception)
5027 % A description of each parameter follows:
5029 % o image: the image.
5031 % o nexus_info: the cache nexus to sync.
5033 % o exception: return any errors or warnings in this structure.
5036 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5037 NexusInfo *nexus_info,ExceptionInfo *exception)
5046 Transfer pixels to the cache.
5048 assert(image != (Image *) NULL);
5049 assert(image->signature == MagickSignature);
5050 if (image->cache == (Cache) NULL)
5051 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5052 cache_info=(CacheInfo *) image->cache;
5053 assert(cache_info->signature == MagickSignature);
5054 if (cache_info->type == UndefinedCache)
5055 return(MagickFalse);
5056 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5058 assert(cache_info->signature == MagickSignature);
5059 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5060 if ((cache_info->metacontent_extent != 0) &&
5061 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5062 return(MagickFalse);
5067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5071 + S y n c A u t h e n t i c P i x e l C a c h e %
5075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5077 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5078 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5079 % otherwise MagickFalse.
5081 % The format of the SyncAuthenticPixelsCache() method is:
5083 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5084 % ExceptionInfo *exception)
5086 % A description of each parameter follows:
5088 % o image: the image.
5090 % o exception: return any errors or warnings in this structure.
5093 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5094 ExceptionInfo *exception)
5100 id = GetOpenMPThreadId();
5105 assert(image != (Image *) NULL);
5106 assert(image->signature == MagickSignature);
5107 assert(image->cache != (Cache) NULL);
5108 cache_info=(CacheInfo *) image->cache;
5109 assert(cache_info->signature == MagickSignature);
5110 assert(id < (int) cache_info->number_threads);
5111 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5121 % S y n c A u t h e n t i c P i x e l s %
5125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5127 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5128 % The method returns MagickTrue if the pixel region is flushed, otherwise
5131 % The format of the SyncAuthenticPixels() method is:
5133 % MagickBooleanType SyncAuthenticPixels(Image *image,
5134 % ExceptionInfo *exception)
5136 % A description of each parameter follows:
5138 % o image: the image.
5140 % o exception: return any errors or warnings in this structure.
5143 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5144 ExceptionInfo *exception)
5150 id = GetOpenMPThreadId();
5155 assert(image != (Image *) NULL);
5156 assert(image->signature == MagickSignature);
5157 assert(image->cache != (Cache) NULL);
5158 cache_info=(CacheInfo *) image->cache;
5159 assert(cache_info->signature == MagickSignature);
5160 if (cache_info->methods.sync_authentic_pixels_handler !=
5161 (SyncAuthenticPixelsHandler) NULL)
5163 status=cache_info->methods.sync_authentic_pixels_handler(image,
5167 assert(id < (int) cache_info->number_threads);
5168 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5178 + S y n c I m a g e P i x e l C a c h e %
5182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5184 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5185 % The method returns MagickTrue if the pixel region is flushed, otherwise
5188 % The format of the SyncImagePixelCache() method is:
5190 % MagickBooleanType SyncImagePixelCache(Image *image,
5191 % ExceptionInfo *exception)
5193 % A description of each parameter follows:
5195 % o image: the image.
5197 % o exception: return any errors or warnings in this structure.
5200 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5201 ExceptionInfo *exception)
5206 assert(image != (Image *) NULL);
5207 assert(exception != (ExceptionInfo *) NULL);
5208 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5209 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5217 + 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 %
5221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5223 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5224 % of the pixel cache.
5226 % The format of the WritePixelCacheMetacontent() method is:
5228 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5229 % NexusInfo *nexus_info,ExceptionInfo *exception)
5231 % A description of each parameter follows:
5233 % o cache_info: the pixel cache.
5235 % o nexus_info: the cache nexus to write the meta-content.
5237 % o exception: return any errors or warnings in this structure.
5240 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5241 NexusInfo *nexus_info,ExceptionInfo *exception)
5251 register const unsigned char
5260 if (cache_info->metacontent_extent == 0)
5261 return(MagickFalse);
5262 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5264 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5265 nexus_info->region.x;
5266 length=(MagickSizeType) nexus_info->region.width*
5267 cache_info->metacontent_extent;
5268 rows=nexus_info->region.height;
5269 extent=(MagickSizeType) length*rows;
5270 p=(unsigned char *) nexus_info->metacontent;
5271 switch (cache_info->type)
5276 register unsigned char
5280 Write associated pixels to memory.
5282 if ((cache_info->columns == nexus_info->region.width) &&
5283 (extent == (MagickSizeType) ((size_t) extent)))
5288 q=(unsigned char *) cache_info->metacontent+offset*
5289 cache_info->metacontent_extent;
5290 for (y=0; y < (ssize_t) rows; y++)
5292 (void) memcpy(q,p,(size_t) length);
5293 p+=nexus_info->region.width*cache_info->metacontent_extent;
5294 q+=cache_info->columns*cache_info->metacontent_extent;
5301 Write associated pixels to disk.
5303 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5305 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5306 cache_info->cache_filename);
5307 return(MagickFalse);
5309 if ((cache_info->columns == nexus_info->region.width) &&
5310 (extent <= MagickMaxBufferExtent))
5315 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5316 for (y=0; y < (ssize_t) rows; y++)
5318 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5319 cache_info->number_channels*sizeof(Quantum)+offset*
5320 cache_info->metacontent_extent,length,(const unsigned char *) p);
5321 if ((MagickSizeType) count != length)
5323 p+=nexus_info->region.width*cache_info->metacontent_extent;
5324 offset+=cache_info->columns;
5326 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5327 (void) ClosePixelCacheOnDisk(cache_info);
5328 if (y < (ssize_t) rows)
5330 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5331 cache_info->cache_filename);
5332 return(MagickFalse);
5339 if ((cache_info->debug != MagickFalse) &&
5340 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5341 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5342 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5343 nexus_info->region.width,(double) nexus_info->region.height,(double)
5344 nexus_info->region.x,(double) nexus_info->region.y);
5349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5353 + W r i t e C a c h e P i x e l s %
5357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5359 % WritePixelCachePixels() writes image pixels to the specified region of the
5362 % The format of the WritePixelCachePixels() method is:
5364 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5365 % NexusInfo *nexus_info,ExceptionInfo *exception)
5367 % A description of each parameter follows:
5369 % o cache_info: the pixel cache.
5371 % o nexus_info: the cache nexus to write the pixels.
5373 % o exception: return any errors or warnings in this structure.
5376 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5377 NexusInfo *nexus_info,ExceptionInfo *exception)
5387 register const Quantum
5396 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5398 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5399 nexus_info->region.x;
5400 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5402 rows=nexus_info->region.height;
5404 p=nexus_info->pixels;
5405 switch (cache_info->type)
5414 Write pixels to memory.
5416 if ((cache_info->columns == nexus_info->region.width) &&
5417 (extent == (MagickSizeType) ((size_t) extent)))
5422 q=cache_info->pixels+offset*cache_info->number_channels;
5423 for (y=0; y < (ssize_t) rows; y++)
5425 (void) memcpy(q,p,(size_t) length);
5426 p+=nexus_info->region.width*cache_info->number_channels;
5427 q+=cache_info->columns*cache_info->number_channels;
5434 Write pixels to disk.
5436 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5438 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5439 cache_info->cache_filename);
5440 return(MagickFalse);
5442 if ((cache_info->columns == nexus_info->region.width) &&
5443 (extent <= MagickMaxBufferExtent))
5448 for (y=0; y < (ssize_t) rows; y++)
5450 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5451 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5453 if ((MagickSizeType) count != length)
5455 p+=nexus_info->region.width*cache_info->number_channels;
5456 offset+=cache_info->columns;
5458 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5459 (void) ClosePixelCacheOnDisk(cache_info);
5460 if (y < (ssize_t) rows)
5462 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5463 cache_info->cache_filename);
5464 return(MagickFalse);
5471 if ((cache_info->debug != MagickFalse) &&
5472 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5473 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5474 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5475 nexus_info->region.width,(double) nexus_info->region.height,(double)
5476 nexus_info->region.x,(double) nexus_info->region.y);