2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/composite-private.h"
50 #include "MagickCore/exception.h"
51 #include "MagickCore/exception-private.h"
52 #include "MagickCore/geometry.h"
53 #include "MagickCore/list.h"
54 #include "MagickCore/log.h"
55 #include "MagickCore/magick.h"
56 #include "MagickCore/memory_.h"
57 #include "MagickCore/pixel.h"
58 #include "MagickCore/pixel-accessor.h"
59 #include "MagickCore/policy.h"
60 #include "MagickCore/quantum.h"
61 #include "MagickCore/random_.h"
62 #include "MagickCore/resource_.h"
63 #include "MagickCore/semaphore.h"
64 #include "MagickCore/splay-tree.h"
65 #include "MagickCore/string_.h"
66 #include "MagickCore/string-private.h"
67 #include "MagickCore/thread-private.h"
68 #include "MagickCore/utility.h"
69 #include "MagickCore/utility-private.h"
70 #if defined(MAGICKCORE_ZLIB_DELEGATE)
77 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
78 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
79 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
84 typedef struct _MagickModulo
114 Forward declarations.
116 #if defined(__cplusplus) || defined(c_plusplus)
121 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
125 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
126 const ssize_t,const size_t,const size_t,ExceptionInfo *),
127 *GetVirtualPixelsCache(const Image *);
130 *GetVirtualMetacontentFromCache(const Image *);
132 static MagickBooleanType
133 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
134 Quantum *,ExceptionInfo *),
135 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
136 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
137 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
138 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
139 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
140 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
141 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
142 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
145 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
146 const size_t,ExceptionInfo *),
147 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
148 const size_t,ExceptionInfo *),
149 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
150 ExceptionInfo *) magick_hot_spot;
152 #if defined(__cplusplus) || defined(c_plusplus)
159 static volatile MagickBooleanType
160 instantiate_cache = MagickFalse;
163 *cache_semaphore = (SemaphoreInfo *) NULL;
166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170 + A c q u i r e P i x e l C a c h e %
174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176 % AcquirePixelCache() acquires a pixel cache.
178 % The format of the AcquirePixelCache() method is:
180 % Cache AcquirePixelCache(const size_t number_threads)
182 % A description of each parameter follows:
184 % o number_threads: the number of nexus threads.
187 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
192 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
193 if (cache_info == (CacheInfo *) NULL)
194 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
195 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
196 cache_info->type=UndefinedCache;
197 cache_info->mode=IOMode;
198 cache_info->colorspace=RGBColorspace;
199 cache_info->file=(-1);
200 cache_info->id=GetMagickThreadId();
201 cache_info->number_threads=number_threads;
202 if (number_threads == 0)
203 cache_info->number_threads=GetOpenMPMaximumThreads();
204 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
205 if (cache_info->nexus_info == (NexusInfo **) NULL)
206 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
207 cache_info->semaphore=AllocateSemaphoreInfo();
208 cache_info->reference_count=1;
209 cache_info->disk_semaphore=AllocateSemaphoreInfo();
210 cache_info->debug=IsEventLogging();
211 cache_info->signature=MagickSignature;
212 return((Cache ) cache_info);
216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
220 % A c q u i r e P i x e l C a c h e N e x u s %
224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
228 % The format of the AcquirePixelCacheNexus method is:
230 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
232 % A description of each parameter follows:
234 % o number_threads: the number of nexus threads.
237 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
245 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
246 sizeof(*nexus_info));
247 if (nexus_info == (NexusInfo **) NULL)
248 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
249 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
250 sizeof(**nexus_info));
251 if (nexus_info[0] == (NexusInfo *) NULL)
252 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
253 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
254 for (i=0; i < (ssize_t) number_threads; i++)
256 nexus_info[i]=(&nexus_info[0][i]);
257 nexus_info[i]->signature=MagickSignature;
263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267 + A c q u i r e P i x e l C a c h e P i x e l s %
271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273 % AcquirePixelCachePixels() returns the pixels associated with the specified
276 % The format of the AcquirePixelCachePixels() method is:
278 % const void *AcquirePixelCachePixels(const Image *image,
279 % MagickSizeType *length,ExceptionInfo *exception)
281 % A description of each parameter follows:
283 % o image: the image.
285 % o length: the pixel cache length.
287 % o exception: return any errors or warnings in this structure.
290 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
291 MagickSizeType *length,ExceptionInfo *exception)
296 assert(image != (const Image *) NULL);
297 assert(image->signature == MagickSignature);
298 assert(exception != (ExceptionInfo *) NULL);
299 assert(exception->signature == MagickSignature);
300 assert(image->cache != (Cache) NULL);
301 cache_info=(CacheInfo *) image->cache;
302 assert(cache_info->signature == MagickSignature);
304 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
305 return((const void *) NULL);
306 *length=cache_info->length;
307 return((const void *) cache_info->pixels);
311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
315 + C a c h e C o m p o n e n t G e n e s i s %
319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321 % CacheComponentGenesis() instantiates the cache component.
323 % The format of the CacheComponentGenesis method is:
325 % MagickBooleanType CacheComponentGenesis(void)
328 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
330 AcquireSemaphoreInfo(&cache_semaphore);
335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339 + C a c h e C o m p o n e n t T e r m i n u s %
343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345 % CacheComponentTerminus() destroys the cache component.
347 % The format of the CacheComponentTerminus() method is:
349 % CacheComponentTerminus(void)
352 MagickPrivate void CacheComponentTerminus(void)
354 if (cache_semaphore == (SemaphoreInfo *) NULL)
355 AcquireSemaphoreInfo(&cache_semaphore);
356 LockSemaphoreInfo(cache_semaphore);
357 instantiate_cache=MagickFalse;
358 UnlockSemaphoreInfo(cache_semaphore);
359 DestroySemaphoreInfo(&cache_semaphore);
363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
367 + C l o n e P i x e l C a c h e %
371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373 % ClonePixelCache() clones a pixel cache.
375 % The format of the ClonePixelCache() method is:
377 % Cache ClonePixelCache(const Cache cache)
379 % A description of each parameter follows:
381 % o cache: the pixel cache.
384 MagickPrivate Cache ClonePixelCache(const Cache cache)
392 assert(cache != NULL);
393 cache_info=(const CacheInfo *) cache;
394 assert(cache_info->signature == MagickSignature);
395 if (cache_info->debug != MagickFalse)
396 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
397 cache_info->filename);
398 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
399 if (clone_info == (Cache) NULL)
400 return((Cache) NULL);
401 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
402 return((Cache ) clone_info);
406 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
410 + C l o n e P i x e l C a c h e P i x e l s %
414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
415 % ClonePixelCachePixels() clones the source pixel cache to the destination
418 % The format of the ClonePixelCachePixels() method is:
420 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
421 % CacheInfo *source_info,ExceptionInfo *exception)
423 % A description of each parameter follows:
425 % o cache_info: the pixel cache.
427 % o source_info: the source pixel cache.
429 % o exception: return any errors or warnings in this structure.
433 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
439 LockSemaphoreInfo(cache_info->disk_semaphore);
440 if (cache_info->file != -1)
442 status=close(cache_info->file);
443 cache_info->file=(-1);
444 RelinquishMagickResource(FileResource,1);
446 UnlockSemaphoreInfo(cache_info->disk_semaphore);
447 return(status == -1 ? MagickFalse : MagickTrue);
450 static inline MagickSizeType MagickMax(const MagickSizeType x,
451 const MagickSizeType y)
458 static inline MagickSizeType MagickMin(const MagickSizeType x,
459 const MagickSizeType y)
466 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
473 Open pixel cache on disk.
475 LockSemaphoreInfo(cache_info->disk_semaphore);
476 if (cache_info->file != -1)
478 UnlockSemaphoreInfo(cache_info->disk_semaphore);
479 return(MagickTrue); /* cache already open */
481 if (*cache_info->cache_filename == '\0')
482 file=AcquireUniqueFileResource(cache_info->cache_filename);
488 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
493 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
494 O_BINARY | O_EXCL,S_MODE);
496 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
502 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
505 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
511 UnlockSemaphoreInfo(cache_info->disk_semaphore);
514 (void) AcquireMagickResource(FileResource,1);
515 cache_info->file=file;
516 cache_info->mode=mode;
517 cache_info->timestamp=time(0);
518 UnlockSemaphoreInfo(cache_info->disk_semaphore);
522 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
523 const MagickOffsetType offset,const MagickSizeType length,
524 unsigned char *restrict buffer)
526 register MagickOffsetType
532 cache_info->timestamp=time(0);
533 #if !defined(MAGICKCORE_HAVE_PREAD)
534 LockSemaphoreInfo(cache_info->disk_semaphore);
535 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
537 UnlockSemaphoreInfo(cache_info->disk_semaphore);
538 return((MagickOffsetType) -1);
542 for (i=0; i < (MagickOffsetType) length; i+=count)
544 #if !defined(MAGICKCORE_HAVE_PREAD)
545 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
546 (MagickSizeType) SSIZE_MAX));
548 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
549 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
560 #if !defined(MAGICKCORE_HAVE_PREAD)
561 UnlockSemaphoreInfo(cache_info->disk_semaphore);
566 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
567 const MagickOffsetType offset,const MagickSizeType length,
568 const unsigned char *restrict buffer)
570 register MagickOffsetType
576 cache_info->timestamp=time(0);
577 #if !defined(MAGICKCORE_HAVE_PWRITE)
578 LockSemaphoreInfo(cache_info->disk_semaphore);
579 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
581 UnlockSemaphoreInfo(cache_info->disk_semaphore);
582 return((MagickOffsetType) -1);
586 for (i=0; i < (MagickOffsetType) length; i+=count)
588 #if !defined(MAGICKCORE_HAVE_PWRITE)
589 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
590 (MagickSizeType) SSIZE_MAX));
592 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
593 (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 length=clone_info->number_channels*sizeof(Quantum);
901 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
902 for ( ; x < (ssize_t) clone_info->columns; x++)
905 Set remaining columns as undefined.
907 if (clone_info->type != DiskCache)
908 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
912 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
913 if ((MagickSizeType) count != length)
919 clone_offset+=length;
922 length=clone_info->number_channels*sizeof(Quantum);
923 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
924 for ( ; y < (ssize_t) clone_info->rows; y++)
927 Set remaining rows as undefined.
929 for (x=0; x < (ssize_t) clone_info->columns; x++)
931 if (clone_info->type != DiskCache)
932 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
936 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
937 if ((MagickSizeType) count != length)
943 clone_offset+=length;
946 if ((cache_info->metacontent_extent != 0) ||
947 (clone_info->metacontent_extent != 0))
952 for (y=0; y < (ssize_t) cache_info->rows; y++)
954 for (x=0; x < (ssize_t) cache_info->columns; x++)
957 Read a set of metacontent.
959 length=cache_info->metacontent_extent;
960 if (cache_info->type != DiskCache)
961 p=(unsigned char *) cache_info->pixels+cache_offset;
964 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
965 if ((MagickSizeType) count != length)
971 cache_offset+=length;
972 if ((y < (ssize_t) clone_info->rows) &&
973 (x < (ssize_t) clone_info->columns))
976 Write a set of metacontent.
978 length=clone_info->metacontent_extent;
979 if (clone_info->type != DiskCache)
980 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
984 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
985 if ((MagickSizeType) count != length)
991 clone_offset+=length;
994 length=clone_info->metacontent_extent;
995 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
996 for ( ; x < (ssize_t) clone_info->columns; x++)
999 Set remaining columns as undefined.
1001 if (clone_info->type != DiskCache)
1002 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1006 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1007 if ((MagickSizeType) count != length)
1013 clone_offset+=length;
1016 length=clone_info->metacontent_extent;
1017 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1018 for ( ; y < (ssize_t) clone_info->rows; y++)
1021 Set remaining rows as undefined.
1023 for (x=0; x < (ssize_t) clone_info->columns; x++)
1025 if (clone_info->type != DiskCache)
1026 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1030 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1031 if ((MagickSizeType) count != length)
1037 clone_offset+=length;
1041 if (clone_info->type == DiskCache)
1042 (void) ClosePixelCacheOnDisk(clone_info);
1043 if (cache_info->type == DiskCache)
1044 (void) ClosePixelCacheOnDisk(cache_info);
1045 blob=(unsigned char *) RelinquishMagickMemory(blob);
1049 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1050 CacheInfo *cache_info,ExceptionInfo *exception)
1056 if (cache_info->type == PingCache)
1058 p=cache_info->channel_map;
1059 q=clone_info->channel_map;
1060 if ((cache_info->columns == clone_info->columns) &&
1061 (cache_info->rows == clone_info->rows) &&
1062 (cache_info->number_channels == clone_info->number_channels) &&
1063 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1064 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1065 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1066 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1074 + C l o n e P i x e l C a c h e M e t h o d s %
1078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1080 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1083 % The format of the ClonePixelCacheMethods() method is:
1085 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1087 % A description of each parameter follows:
1089 % o clone: Specifies a pointer to a Cache structure.
1091 % o cache: the pixel cache.
1094 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1100 assert(clone != (Cache) NULL);
1101 source_info=(CacheInfo *) clone;
1102 assert(source_info->signature == MagickSignature);
1103 if (source_info->debug != MagickFalse)
1104 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1105 source_info->filename);
1106 assert(cache != (Cache) NULL);
1107 cache_info=(CacheInfo *) cache;
1108 assert(cache_info->signature == MagickSignature);
1109 source_info->methods=cache_info->methods;
1113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1117 + D e s t r o y I m a g e P i x e l C a c h e %
1121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1123 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1125 % The format of the DestroyImagePixelCache() method is:
1127 % void DestroyImagePixelCache(Image *image)
1129 % A description of each parameter follows:
1131 % o image: the image.
1134 static void DestroyImagePixelCache(Image *image)
1136 assert(image != (Image *) NULL);
1137 assert(image->signature == MagickSignature);
1138 if (image->debug != MagickFalse)
1139 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1140 if (image->cache == (void *) NULL)
1142 image->cache=DestroyPixelCache(image->cache);
1146 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1150 + D e s t r o y I m a g e P i x e l s %
1154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1156 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1158 % The format of the DestroyImagePixels() method is:
1160 % void DestroyImagePixels(Image *image)
1162 % A description of each parameter follows:
1164 % o image: the image.
1167 MagickExport void DestroyImagePixels(Image *image)
1172 assert(image != (const Image *) NULL);
1173 assert(image->signature == MagickSignature);
1174 if (image->debug != MagickFalse)
1175 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1176 assert(image->cache != (Cache) NULL);
1177 cache_info=(CacheInfo *) image->cache;
1178 assert(cache_info->signature == MagickSignature);
1179 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1181 cache_info->methods.destroy_pixel_handler(image);
1184 image->cache=DestroyPixelCache(image->cache);
1188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1192 + D e s t r o y P i x e l C a c h e %
1196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1200 % The format of the DestroyPixelCache() method is:
1202 % Cache DestroyPixelCache(Cache cache)
1204 % A description of each parameter follows:
1206 % o cache: the pixel cache.
1210 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1212 switch (cache_info->type)
1216 if (cache_info->mapped == MagickFalse)
1217 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
1218 cache_info->pixels);
1220 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1221 (size_t) cache_info->length);
1222 RelinquishMagickResource(MemoryResource,cache_info->length);
1227 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1228 cache_info->length);
1229 RelinquishMagickResource(MapResource,cache_info->length);
1233 if (cache_info->file != -1)
1234 (void) ClosePixelCacheOnDisk(cache_info);
1235 RelinquishMagickResource(DiskResource,cache_info->length);
1241 cache_info->type=UndefinedCache;
1242 cache_info->mapped=MagickFalse;
1243 cache_info->metacontent=(void *) NULL;
1246 MagickPrivate Cache DestroyPixelCache(Cache cache)
1251 assert(cache != (Cache) NULL);
1252 cache_info=(CacheInfo *) cache;
1253 assert(cache_info->signature == MagickSignature);
1254 if (cache_info->debug != MagickFalse)
1255 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1256 cache_info->filename);
1257 LockSemaphoreInfo(cache_info->semaphore);
1258 cache_info->reference_count--;
1259 if (cache_info->reference_count != 0)
1261 UnlockSemaphoreInfo(cache_info->semaphore);
1262 return((Cache) NULL);
1264 UnlockSemaphoreInfo(cache_info->semaphore);
1265 if (cache_info->debug != MagickFalse)
1268 message[MaxTextExtent];
1270 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1271 cache_info->filename);
1272 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1274 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1275 (cache_info->type != DiskCache)))
1276 RelinquishPixelCachePixels(cache_info);
1279 RelinquishPixelCachePixels(cache_info);
1280 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1282 *cache_info->cache_filename='\0';
1283 if (cache_info->nexus_info != (NexusInfo **) NULL)
1284 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1285 cache_info->number_threads);
1286 if (cache_info->random_info != (RandomInfo *) NULL)
1287 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1288 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1289 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1290 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1291 DestroySemaphoreInfo(&cache_info->semaphore);
1292 cache_info->signature=(~MagickSignature);
1293 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1303 + D e s t r o y P i x e l C a c h e N e x u s %
1307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1311 % The format of the DestroyPixelCacheNexus() method is:
1313 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1314 % const size_t number_threads)
1316 % A description of each parameter follows:
1318 % o nexus_info: the nexus to destroy.
1320 % o number_threads: the number of nexus threads.
1324 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1326 if (nexus_info->mapped == MagickFalse)
1327 (void) RelinquishAlignedMemory(nexus_info->cache);
1329 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1330 nexus_info->cache=(Quantum *) NULL;
1331 nexus_info->pixels=(Quantum *) NULL;
1332 nexus_info->metacontent=(void *) NULL;
1333 nexus_info->length=0;
1334 nexus_info->mapped=MagickFalse;
1337 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1338 const size_t number_threads)
1343 assert(nexus_info != (NexusInfo **) NULL);
1344 for (i=0; i < (ssize_t) number_threads; i++)
1346 if (nexus_info[i]->cache != (Quantum *) NULL)
1347 RelinquishCacheNexusPixels(nexus_info[i]);
1348 nexus_info[i]->signature=(~MagickSignature);
1350 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1351 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360 % G e t A u t h e n t i c M e t a c o n t e n t %
1364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1366 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1367 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1368 % returned if the associated pixels are not available.
1370 % The format of the GetAuthenticMetacontent() method is:
1372 % void *GetAuthenticMetacontent(const Image *image)
1374 % A description of each parameter follows:
1376 % o image: the image.
1379 MagickExport void *GetAuthenticMetacontent(const Image *image)
1385 id = GetOpenMPThreadId();
1390 assert(image != (const Image *) NULL);
1391 assert(image->signature == MagickSignature);
1392 assert(image->cache != (Cache) NULL);
1393 cache_info=(CacheInfo *) image->cache;
1394 assert(cache_info->signature == MagickSignature);
1395 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1396 (GetAuthenticMetacontentFromHandler) NULL)
1398 metacontent=cache_info->methods.
1399 get_authentic_metacontent_from_handler(image);
1400 return(metacontent);
1402 assert(id < (int) cache_info->number_threads);
1403 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1404 cache_info->nexus_info[id]);
1405 return(metacontent);
1409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413 + 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 %
1417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1420 % with the last call to QueueAuthenticPixelsCache() or
1421 % GetAuthenticPixelsCache().
1423 % The format of the GetAuthenticMetacontentFromCache() method is:
1425 % void *GetAuthenticMetacontentFromCache(const Image *image)
1427 % A description of each parameter follows:
1429 % o image: the image.
1432 static void *GetAuthenticMetacontentFromCache(const Image *image)
1438 id = GetOpenMPThreadId();
1443 assert(image != (const Image *) NULL);
1444 assert(image->signature == MagickSignature);
1445 assert(image->cache != (Cache) NULL);
1446 cache_info=(CacheInfo *) image->cache;
1447 assert(cache_info->signature == MagickSignature);
1448 assert(id < (int) cache_info->number_threads);
1449 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1450 cache_info->nexus_info[id]);
1451 return(metacontent);
1455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1459 + 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 %
1463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1466 % disk pixel cache as defined by the geometry parameters. A pointer to the
1467 % pixels is returned if the pixels are transferred, otherwise a NULL is
1470 % The format of the GetAuthenticPixelCacheNexus() method is:
1472 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1473 % const ssize_t y,const size_t columns,const size_t rows,
1474 % NexusInfo *nexus_info,ExceptionInfo *exception)
1476 % A description of each parameter follows:
1478 % o image: the image.
1480 % o x,y,columns,rows: These values define the perimeter of a region of
1483 % o nexus_info: the cache nexus to return.
1485 % o exception: return any errors or warnings in this structure.
1489 static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
1490 NexusInfo *nexus_info)
1498 if (cache_info->type == PingCache)
1500 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1501 nexus_info->region.x;
1502 status=nexus_info->pixels == (cache_info->pixels+offset*
1503 cache_info->number_channels) ? MagickTrue : MagickFalse;
1507 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1508 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1509 NexusInfo *nexus_info,ExceptionInfo *exception)
1518 Transfer pixels from the cache.
1520 assert(image != (Image *) NULL);
1521 assert(image->signature == MagickSignature);
1522 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1524 if (q == (Quantum *) NULL)
1525 return((Quantum *) NULL);
1526 cache_info=(CacheInfo *) image->cache;
1527 assert(cache_info->signature == MagickSignature);
1528 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1530 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1531 return((Quantum *) NULL);
1532 if (cache_info->metacontent_extent != 0)
1533 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1534 return((Quantum *) NULL);
1539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1543 + 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 %
1547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1549 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1550 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1552 % The format of the GetAuthenticPixelsFromCache() method is:
1554 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1556 % A description of each parameter follows:
1558 % o image: the image.
1561 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1567 id = GetOpenMPThreadId();
1569 assert(image != (const Image *) NULL);
1570 assert(image->signature == MagickSignature);
1571 assert(image->cache != (Cache) NULL);
1572 cache_info=(CacheInfo *) image->cache;
1573 assert(cache_info->signature == MagickSignature);
1574 assert(id < (int) cache_info->number_threads);
1575 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1583 % G e t A u t h e n t i c P i x e l Q u e u e %
1587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589 % GetAuthenticPixelQueue() returns the authentic pixels associated
1590 % corresponding with the last call to QueueAuthenticPixels() or
1591 % GetAuthenticPixels().
1593 % The format of the GetAuthenticPixelQueue() method is:
1595 % Quantum *GetAuthenticPixelQueue(const Image image)
1597 % A description of each parameter follows:
1599 % o image: the image.
1602 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1608 id = GetOpenMPThreadId();
1610 assert(image != (const Image *) NULL);
1611 assert(image->signature == MagickSignature);
1612 assert(image->cache != (Cache) NULL);
1613 cache_info=(CacheInfo *) image->cache;
1614 assert(cache_info->signature == MagickSignature);
1615 if (cache_info->methods.get_authentic_pixels_from_handler !=
1616 (GetAuthenticPixelsFromHandler) NULL)
1617 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1618 assert(id < (int) cache_info->number_threads);
1619 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1627 % G e t A u t h e n t i c P i x e l s %
1630 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1632 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1633 % region is successfully accessed, a pointer to a Quantum array
1634 % representing the region is returned, otherwise NULL is returned.
1636 % The returned pointer may point to a temporary working copy of the pixels
1637 % or it may point to the original pixels in memory. Performance is maximized
1638 % if the selected region is part of one row, or one or more full rows, since
1639 % then there is opportunity to access the pixels in-place (without a copy)
1640 % if the image is in memory, or in a memory-mapped file. The returned pointer
1641 % must *never* be deallocated by the user.
1643 % Pixels accessed via the returned pointer represent a simple array of type
1644 % Quantum. If the image has corresponding metacontent,call
1645 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1646 % meta-content corresponding to the region. Once the Quantum array has
1647 % been updated, the changes must be saved back to the underlying image using
1648 % SyncAuthenticPixels() or they may be lost.
1650 % The format of the GetAuthenticPixels() method is:
1652 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1653 % const ssize_t y,const size_t columns,const size_t rows,
1654 % ExceptionInfo *exception)
1656 % A description of each parameter follows:
1658 % o image: the image.
1660 % o x,y,columns,rows: These values define the perimeter of a region of
1663 % o exception: return any errors or warnings in this structure.
1666 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1667 const ssize_t y,const size_t columns,const size_t rows,
1668 ExceptionInfo *exception)
1674 id = GetOpenMPThreadId();
1679 assert(image != (Image *) NULL);
1680 assert(image->signature == MagickSignature);
1681 assert(image->cache != (Cache) NULL);
1682 cache_info=(CacheInfo *) image->cache;
1683 assert(cache_info->signature == MagickSignature);
1684 if (cache_info->methods.get_authentic_pixels_handler !=
1685 (GetAuthenticPixelsHandler) NULL)
1687 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1691 assert(id < (int) cache_info->number_threads);
1692 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1693 cache_info->nexus_info[id],exception);
1698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1702 + G e t A u t h e n t i c P i x e l s C a c h e %
1706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1708 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1709 % as defined by the geometry parameters. A pointer to the pixels is returned
1710 % if the pixels are transferred, otherwise a NULL is returned.
1712 % The format of the GetAuthenticPixelsCache() method is:
1714 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1715 % const ssize_t y,const size_t columns,const size_t rows,
1716 % ExceptionInfo *exception)
1718 % A description of each parameter follows:
1720 % o image: the image.
1722 % o x,y,columns,rows: These values define the perimeter of a region of
1725 % o exception: return any errors or warnings in this structure.
1728 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1729 const ssize_t y,const size_t columns,const size_t rows,
1730 ExceptionInfo *exception)
1736 id = GetOpenMPThreadId();
1741 assert(image != (const Image *) NULL);
1742 assert(image->signature == MagickSignature);
1743 assert(image->cache != (Cache) NULL);
1744 cache_info=(CacheInfo *) image->cache;
1745 if (cache_info == (Cache) NULL)
1746 return((Quantum *) NULL);
1747 assert(cache_info->signature == MagickSignature);
1748 assert(id < (int) cache_info->number_threads);
1749 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1750 cache_info->nexus_info[id],exception);
1755 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1759 + G e t I m a g e E x t e n t %
1763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765 % GetImageExtent() returns the extent of the pixels associated corresponding
1766 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1768 % The format of the GetImageExtent() method is:
1770 % MagickSizeType GetImageExtent(const Image *image)
1772 % A description of each parameter follows:
1774 % o image: the image.
1777 MagickExport MagickSizeType GetImageExtent(const Image *image)
1783 id = GetOpenMPThreadId();
1785 assert(image != (Image *) NULL);
1786 assert(image->signature == MagickSignature);
1787 if (image->debug != MagickFalse)
1788 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1789 assert(image->cache != (Cache) NULL);
1790 cache_info=(CacheInfo *) image->cache;
1791 assert(cache_info->signature == MagickSignature);
1792 assert(id < (int) cache_info->number_threads);
1793 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1801 + G e t I m a g e P i x e l C a c h e %
1805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1807 % GetImagePixelCache() ensures that there is only a single reference to the
1808 % pixel cache to be modified, updating the provided cache pointer to point to
1809 % a clone of the original pixel cache if necessary.
1811 % The format of the GetImagePixelCache method is:
1813 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1814 % ExceptionInfo *exception)
1816 % A description of each parameter follows:
1818 % o image: the image.
1820 % o clone: any value other than MagickFalse clones the cache pixels.
1822 % o exception: return any errors or warnings in this structure.
1826 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1836 Does the image match the pixel cache morphology?
1838 cache_info=(CacheInfo *) image->cache;
1839 p=image->channel_map;
1840 q=cache_info->channel_map;
1841 if ((image->storage_class != cache_info->storage_class) ||
1842 (image->colorspace != cache_info->colorspace) ||
1843 (image->matte != cache_info->matte) ||
1844 (image->mask != cache_info->mask) ||
1845 (image->columns != cache_info->columns) ||
1846 (image->rows != cache_info->rows) ||
1847 (image->number_channels != cache_info->number_channels) ||
1848 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1849 (image->metacontent_extent != cache_info->metacontent_extent) ||
1850 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1851 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1852 return(MagickFalse);
1856 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1857 ExceptionInfo *exception)
1866 static MagickSizeType
1872 cache_timestamp = 0;
1875 LockSemaphoreInfo(image->semaphore);
1876 if (cpu_throttle == 0)
1882 Set CPU throttle in milleseconds.
1884 cpu_throttle=MagickResourceInfinity;
1885 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1886 if (limit == (char *) NULL)
1887 limit=GetPolicyValue("throttle");
1888 if (limit != (char *) NULL)
1890 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1891 limit=DestroyString(limit);
1894 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1895 MagickDelay(cpu_throttle);
1896 if (time_limit == 0)
1899 Set the exire time in seconds.
1901 time_limit=GetMagickResourceLimit(TimeResource);
1902 cache_timestamp=time((time_t *) NULL);
1904 if ((time_limit != MagickResourceInfinity) &&
1905 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1906 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1907 assert(image->cache != (Cache) NULL);
1908 cache_info=(CacheInfo *) image->cache;
1909 destroy=MagickFalse;
1910 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1912 LockSemaphoreInfo(cache_info->semaphore);
1913 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1924 clone_image=(*image);
1925 clone_image.semaphore=AllocateSemaphoreInfo();
1926 clone_image.reference_count=1;
1927 clone_image.cache=ClonePixelCache(cache_info);
1928 clone_info=(CacheInfo *) clone_image.cache;
1929 status=OpenPixelCache(&clone_image,IOMode,exception);
1930 if (status != MagickFalse)
1932 if (clone != MagickFalse)
1933 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1934 if (status != MagickFalse)
1936 if (cache_info->mode == ReadMode)
1937 cache_info->nexus_info=(NexusInfo **) NULL;
1939 image->cache=clone_image.cache;
1942 DestroySemaphoreInfo(&clone_image.semaphore);
1944 UnlockSemaphoreInfo(cache_info->semaphore);
1946 if (destroy != MagickFalse)
1947 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1948 if (status != MagickFalse)
1951 Ensure the image matches the pixel cache morphology.
1953 image->taint=MagickTrue;
1954 image->type=UndefinedType;
1955 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1957 status=OpenPixelCache(image,IOMode,exception);
1958 cache_info=(CacheInfo *) image->cache;
1959 if (cache_info->type == DiskCache)
1960 (void) ClosePixelCacheOnDisk(cache_info);
1963 UnlockSemaphoreInfo(image->semaphore);
1964 if (status == MagickFalse)
1965 return((Cache) NULL);
1966 return(image->cache);
1970 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1974 % G e t O n e A u t h e n t i c P i x e l %
1978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1981 % location. The image background color is returned if an error occurs.
1983 % The format of the GetOneAuthenticPixel() method is:
1985 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1986 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1988 % A description of each parameter follows:
1990 % o image: the image.
1992 % o x,y: These values define the location of the pixel to return.
1994 % o pixel: return a pixel at the specified (x,y) location.
1996 % o exception: return any errors or warnings in this structure.
1999 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2000 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2011 assert(image != (Image *) NULL);
2012 assert(image->signature == MagickSignature);
2013 assert(image->cache != (Cache) NULL);
2014 cache_info=(CacheInfo *) image->cache;
2015 assert(cache_info->signature == MagickSignature);
2016 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2017 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2018 (GetOneAuthenticPixelFromHandler) NULL)
2019 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2021 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2022 if (q == (Quantum *) NULL)
2024 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2025 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2026 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2027 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2028 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2029 return(MagickFalse);
2031 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2036 channel=GetPixelChannelMapChannel(image,i);
2037 pixel[channel]=q[i];
2043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2047 + 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 %
2051 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2053 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2054 % location. The image background color is returned if an error occurs.
2056 % The format of the GetOneAuthenticPixelFromCache() method is:
2058 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2059 % const ssize_t x,const ssize_t y,Quantum *pixel,
2060 % ExceptionInfo *exception)
2062 % A description of each parameter follows:
2064 % o image: the image.
2066 % o x,y: These values define the location of the pixel to return.
2068 % o pixel: return a pixel at the specified (x,y) location.
2070 % o exception: return any errors or warnings in this structure.
2073 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2074 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2080 id = GetOpenMPThreadId();
2088 assert(image != (const Image *) NULL);
2089 assert(image->signature == MagickSignature);
2090 assert(image->cache != (Cache) NULL);
2091 cache_info=(CacheInfo *) image->cache;
2092 assert(cache_info->signature == MagickSignature);
2093 assert(id < (int) cache_info->number_threads);
2094 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2095 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2097 if (q == (Quantum *) NULL)
2099 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2100 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2101 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2102 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2103 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2104 return(MagickFalse);
2106 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2111 channel=GetPixelChannelMapChannel(image,i);
2112 pixel[channel]=q[i];
2118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2122 % G e t O n e V i r t u a l P i x e l %
2126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2128 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2129 % (x,y) location. The image background color is returned if an error occurs.
2130 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2132 % The format of the GetOneVirtualPixel() method is:
2134 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2135 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2137 % A description of each parameter follows:
2139 % o image: the image.
2141 % o x,y: These values define the location of the pixel to return.
2143 % o pixel: return a pixel at the specified (x,y) location.
2145 % o exception: return any errors or warnings in this structure.
2148 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2149 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2155 id = GetOpenMPThreadId();
2163 assert(image != (const Image *) NULL);
2164 assert(image->signature == MagickSignature);
2165 assert(image->cache != (Cache) NULL);
2166 cache_info=(CacheInfo *) image->cache;
2167 assert(cache_info->signature == MagickSignature);
2168 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2169 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2170 (GetOneVirtualPixelFromHandler) NULL)
2171 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2172 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2173 assert(id < (int) cache_info->number_threads);
2174 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2175 1UL,1UL,cache_info->nexus_info[id],exception);
2176 if (p == (const Quantum *) NULL)
2178 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2179 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2180 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2181 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2182 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2183 return(MagickFalse);
2185 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2190 channel=GetPixelChannelMapChannel(image,i);
2191 pixel[channel]=p[i];
2197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2201 + 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 %
2205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2207 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2208 % specified (x,y) location. The image background color is returned if an
2211 % The format of the GetOneVirtualPixelFromCache() method is:
2213 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2214 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2215 % Quantum *pixel,ExceptionInfo *exception)
2217 % A description of each parameter follows:
2219 % o image: the image.
2221 % o virtual_pixel_method: the virtual pixel method.
2223 % o x,y: These values define the location of the pixel to return.
2225 % o pixel: return a pixel at the specified (x,y) location.
2227 % o exception: return any errors or warnings in this structure.
2230 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2231 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2232 Quantum *pixel,ExceptionInfo *exception)
2238 id = GetOpenMPThreadId();
2246 assert(image != (const Image *) NULL);
2247 assert(image->signature == MagickSignature);
2248 assert(image->cache != (Cache) NULL);
2249 cache_info=(CacheInfo *) image->cache;
2250 assert(cache_info->signature == MagickSignature);
2251 assert(id < (int) cache_info->number_threads);
2252 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2253 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2254 cache_info->nexus_info[id],exception);
2255 if (p == (const Quantum *) NULL)
2257 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2258 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2259 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2260 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2261 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2262 return(MagickFalse);
2264 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2269 channel=GetPixelChannelMapChannel(image,i);
2270 pixel[channel]=p[i];
2276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2280 % G e t O n e V i r t u a l P i x e l I n f o %
2284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2286 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2287 % location. The image background color is returned if an error occurs. If
2288 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2290 % The format of the GetOneVirtualPixelInfo() method is:
2292 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2293 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2294 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2296 % A description of each parameter follows:
2298 % o image: the image.
2300 % o virtual_pixel_method: the virtual pixel method.
2302 % o x,y: these values define the location of the pixel to return.
2304 % o pixel: return a pixel at the specified (x,y) location.
2306 % o exception: return any errors or warnings in this structure.
2309 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2310 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2311 PixelInfo *pixel,ExceptionInfo *exception)
2317 id = GetOpenMPThreadId();
2319 register const Quantum
2322 assert(image != (const Image *) NULL);
2323 assert(image->signature == MagickSignature);
2324 assert(image->cache != (Cache) NULL);
2325 cache_info=(CacheInfo *) image->cache;
2326 assert(cache_info->signature == MagickSignature);
2327 assert(id < (int) cache_info->number_threads);
2328 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2329 cache_info->nexus_info[id],exception);
2330 GetPixelInfo(image,pixel);
2331 if (p == (const Quantum *) NULL)
2332 return(MagickFalse);
2333 GetPixelInfoPixel(image,p,pixel);
2338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2342 + G e t P i x e l C a c h e C o l o r s p a c e %
2346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2348 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2350 % The format of the GetPixelCacheColorspace() method is:
2352 % Colorspace GetPixelCacheColorspace(Cache cache)
2354 % A description of each parameter follows:
2356 % o cache: the pixel cache.
2359 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2364 assert(cache != (Cache) NULL);
2365 cache_info=(CacheInfo *) cache;
2366 assert(cache_info->signature == MagickSignature);
2367 if (cache_info->debug != MagickFalse)
2368 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2369 cache_info->filename);
2370 return(cache_info->colorspace);
2374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2378 + G e t P i x e l C a c h e M e t h o d s %
2382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2384 % GetPixelCacheMethods() initializes the CacheMethods structure.
2386 % The format of the GetPixelCacheMethods() method is:
2388 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2390 % A description of each parameter follows:
2392 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2395 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2397 assert(cache_methods != (CacheMethods *) NULL);
2398 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2399 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2400 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2401 cache_methods->get_virtual_metacontent_from_handler=
2402 GetVirtualMetacontentFromCache;
2403 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2404 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2405 cache_methods->get_authentic_metacontent_from_handler=
2406 GetAuthenticMetacontentFromCache;
2407 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2408 cache_methods->get_one_authentic_pixel_from_handler=
2409 GetOneAuthenticPixelFromCache;
2410 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2411 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2412 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2420 + G e t P i x e l C a c h e N e x u s E x t e n t %
2424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2426 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2427 % corresponding with the last call to SetPixelCacheNexusPixels() or
2428 % GetPixelCacheNexusPixels().
2430 % The format of the GetPixelCacheNexusExtent() method is:
2432 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2433 % NexusInfo *nexus_info)
2435 % A description of each parameter follows:
2437 % o nexus_info: the nexus info.
2440 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2441 NexusInfo *nexus_info)
2449 assert(cache != NULL);
2450 cache_info=(CacheInfo *) cache;
2451 assert(cache_info->signature == MagickSignature);
2452 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2454 return((MagickSizeType) cache_info->columns*cache_info->rows);
2459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2463 + 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 %
2467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2469 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2472 % The format of the GetPixelCacheNexusMetacontent() method is:
2474 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2475 % NexusInfo *nexus_info)
2477 % A description of each parameter follows:
2479 % o cache: the pixel cache.
2481 % o nexus_info: the cache nexus to return the meta-content.
2484 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2485 NexusInfo *nexus_info)
2490 assert(cache != NULL);
2491 cache_info=(CacheInfo *) cache;
2492 assert(cache_info->signature == MagickSignature);
2493 if (cache_info->storage_class == UndefinedClass)
2494 return((void *) NULL);
2495 return(nexus_info->metacontent);
2499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2503 + G e t P i x e l C a c h e N e x u s P i x e l s %
2507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2509 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2512 % The format of the GetPixelCacheNexusPixels() method is:
2514 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2515 % NexusInfo *nexus_info)
2517 % A description of each parameter follows:
2519 % o cache: the pixel cache.
2521 % o nexus_info: the cache nexus to return the pixels.
2524 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2525 NexusInfo *nexus_info)
2530 assert(cache != NULL);
2531 cache_info=(CacheInfo *) cache;
2532 assert(cache_info->signature == MagickSignature);
2533 if (cache_info->storage_class == UndefinedClass)
2534 return((Quantum *) NULL);
2535 return(nexus_info->pixels);
2539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2543 + G e t P i x e l C a c h e P i x e l s %
2547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2549 % GetPixelCachePixels() returns the pixels associated with the specified image.
2551 % The format of the GetPixelCachePixels() method is:
2553 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2554 % ExceptionInfo *exception)
2556 % A description of each parameter follows:
2558 % o image: the image.
2560 % o length: the pixel cache length.
2562 % o exception: return any errors or warnings in this structure.
2565 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2566 ExceptionInfo *exception)
2571 assert(image != (const Image *) NULL);
2572 assert(image->signature == MagickSignature);
2573 assert(image->cache != (Cache) NULL);
2574 assert(length != (MagickSizeType *) NULL);
2575 assert(exception != (ExceptionInfo *) NULL);
2576 assert(exception->signature == MagickSignature);
2577 cache_info=(CacheInfo *) image->cache;
2578 assert(cache_info->signature == MagickSignature);
2580 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2581 return((void *) NULL);
2582 *length=cache_info->length;
2583 return((void *) cache_info->pixels);
2587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591 + 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 %
2595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2597 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2599 % The format of the GetPixelCacheStorageClass() method is:
2601 % ClassType GetPixelCacheStorageClass(Cache cache)
2603 % A description of each parameter follows:
2605 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2607 % o cache: the pixel cache.
2610 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2615 assert(cache != (Cache) NULL);
2616 cache_info=(CacheInfo *) cache;
2617 assert(cache_info->signature == MagickSignature);
2618 if (cache_info->debug != MagickFalse)
2619 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2620 cache_info->filename);
2621 return(cache_info->storage_class);
2625 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2629 + G e t P i x e l C a c h e T i l e S i z e %
2633 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2635 % GetPixelCacheTileSize() returns the pixel cache tile size.
2637 % The format of the GetPixelCacheTileSize() method is:
2639 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2642 % A description of each parameter follows:
2644 % o image: the image.
2646 % o width: the optimize cache tile width in pixels.
2648 % o height: the optimize cache tile height in pixels.
2651 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2657 assert(image != (Image *) NULL);
2658 assert(image->signature == MagickSignature);
2659 if (image->debug != MagickFalse)
2660 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2661 cache_info=(CacheInfo *) image->cache;
2662 assert(cache_info->signature == MagickSignature);
2663 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2664 if (GetPixelCacheType(image) == DiskCache)
2665 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2674 + G e t P i x e l C a c h e T y p e %
2678 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2680 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2682 % The format of the GetPixelCacheType() method is:
2684 % CacheType GetPixelCacheType(const Image *image)
2686 % A description of each parameter follows:
2688 % o image: the image.
2691 MagickPrivate CacheType GetPixelCacheType(const Image *image)
2696 assert(image != (Image *) NULL);
2697 assert(image->signature == MagickSignature);
2698 assert(image->cache != (Cache) NULL);
2699 cache_info=(CacheInfo *) image->cache;
2700 assert(cache_info->signature == MagickSignature);
2701 return(cache_info->type);
2705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2709 + G e t P i x e l C a c h e V i r t u a l M e t h o d %
2713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2715 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2716 % pixel cache. A virtual pixel is any pixel access that is outside the
2717 % boundaries of the image cache.
2719 % The format of the GetPixelCacheVirtualMethod() method is:
2721 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2723 % A description of each parameter follows:
2725 % o image: the image.
2728 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2733 assert(image != (Image *) NULL);
2734 assert(image->signature == MagickSignature);
2735 assert(image->cache != (Cache) NULL);
2736 cache_info=(CacheInfo *) image->cache;
2737 assert(cache_info->signature == MagickSignature);
2738 return(cache_info->virtual_pixel_method);
2742 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2746 + G e t V i r t u a l M e t a c o n t e n t F r o m C a c h e %
2750 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2752 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2753 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2755 % The format of the GetVirtualMetacontentFromCache() method is:
2757 % void *GetVirtualMetacontentFromCache(const Image *image)
2759 % A description of each parameter follows:
2761 % o image: the image.
2764 static const void *GetVirtualMetacontentFromCache(const Image *image)
2770 id = GetOpenMPThreadId();
2775 assert(image != (const Image *) NULL);
2776 assert(image->signature == MagickSignature);
2777 assert(image->cache != (Cache) NULL);
2778 cache_info=(CacheInfo *) image->cache;
2779 assert(cache_info->signature == MagickSignature);
2780 assert(id < (int) cache_info->number_threads);
2781 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2782 cache_info->nexus_info[id]);
2783 return(metacontent);
2787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2791 + G e t V i r t u a l M e t a c o n t e n t F r o m N e x u s %
2795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2797 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2800 % The format of the GetVirtualMetacontentFromNexus() method is:
2802 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2803 % NexusInfo *nexus_info)
2805 % A description of each parameter follows:
2807 % o cache: the pixel cache.
2809 % o nexus_info: the cache nexus to return the meta-content.
2812 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2813 NexusInfo *nexus_info)
2818 assert(cache != (Cache) NULL);
2819 cache_info=(CacheInfo *) cache;
2820 assert(cache_info->signature == MagickSignature);
2821 if (cache_info->storage_class == UndefinedClass)
2822 return((void *) NULL);
2823 return(nexus_info->metacontent);
2827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2831 % G e t V i r t u a l M e t a c o n t e n t %
2835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2837 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2838 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2839 % returned if the meta-content are not available.
2841 % The format of the GetVirtualMetacontent() method is:
2843 % const void *GetVirtualMetacontent(const Image *image)
2845 % A description of each parameter follows:
2847 % o image: the image.
2850 MagickExport const void *GetVirtualMetacontent(const Image *image)
2856 id = GetOpenMPThreadId();
2861 assert(image != (const Image *) NULL);
2862 assert(image->signature == MagickSignature);
2863 assert(image->cache != (Cache) NULL);
2864 cache_info=(CacheInfo *) image->cache;
2865 assert(cache_info->signature == MagickSignature);
2866 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2867 if (metacontent != (GetVirtualMetacontentFromHandler) NULL)
2868 return(metacontent);
2869 assert(id < (int) cache_info->number_threads);
2870 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2871 cache_info->nexus_info[id]);
2872 return(metacontent);
2876 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2880 + G e t V i r t u a l P i x e l s F r o m N e x u s %
2884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2886 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2887 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2888 % is returned if the pixels are transferred, otherwise a NULL is returned.
2890 % The format of the GetVirtualPixelsFromNexus() method is:
2892 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2893 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2894 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2895 % ExceptionInfo *exception)
2897 % A description of each parameter follows:
2899 % o image: the image.
2901 % o virtual_pixel_method: the virtual pixel method.
2903 % o x,y,columns,rows: These values define the perimeter of a region of
2906 % o nexus_info: the cache nexus to acquire.
2908 % o exception: return any errors or warnings in this structure.
2915 0, 48, 12, 60, 3, 51, 15, 63,
2916 32, 16, 44, 28, 35, 19, 47, 31,
2917 8, 56, 4, 52, 11, 59, 7, 55,
2918 40, 24, 36, 20, 43, 27, 39, 23,
2919 2, 50, 14, 62, 1, 49, 13, 61,
2920 34, 18, 46, 30, 33, 17, 45, 29,
2921 10, 58, 6, 54, 9, 57, 5, 53,
2922 42, 26, 38, 22, 41, 25, 37, 21
2925 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2930 index=x+DitherMatrix[x & 0x07]-32L;
2933 if (index >= (ssize_t) columns)
2934 return((ssize_t) columns-1L);
2938 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2943 index=y+DitherMatrix[y & 0x07]-32L;
2946 if (index >= (ssize_t) rows)
2947 return((ssize_t) rows-1L);
2951 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2955 if (x >= (ssize_t) columns)
2956 return((ssize_t) (columns-1));
2960 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2964 if (y >= (ssize_t) rows)
2965 return((ssize_t) (rows-1));
2969 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2971 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2974 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2976 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2979 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2980 const size_t extent)
2986 Compute the remainder of dividing offset by extent. It returns not only
2987 the quotient (tile the offset falls in) but also the positive remainer
2988 within that tile such that 0 <= remainder < extent. This method is
2989 essentially a ldiv() using a floored modulo division rather than the
2990 normal default truncated modulo division.
2992 modulo.quotient=offset/(ssize_t) extent;
2995 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2999 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3000 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3001 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3002 ExceptionInfo *exception)
3019 virtual_pixel[CompositePixelChannel];
3024 register const Quantum
3037 register unsigned char
3044 *virtual_metacontent;
3049 assert(image != (const Image *) NULL);
3050 assert(image->signature == MagickSignature);
3051 assert(image->cache != (Cache) NULL);
3052 cache_info=(CacheInfo *) image->cache;
3053 assert(cache_info->signature == MagickSignature);
3054 if (cache_info->type == UndefinedCache)
3055 return((const Quantum *) NULL);
3058 region.width=columns;
3060 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3061 if (pixels == (Quantum *) NULL)
3062 return((const Quantum *) NULL);
3064 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3065 nexus_info->region.x;
3066 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3067 nexus_info->region.width-1L;
3068 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3069 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3070 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3071 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3077 Pixel request is inside cache extents.
3079 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3081 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3082 if (status == MagickFalse)
3083 return((const Quantum *) NULL);
3084 if (cache_info->metacontent_extent != 0)
3086 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3087 if (status == MagickFalse)
3088 return((const Quantum *) NULL);
3093 Pixel request is outside cache extents.
3095 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3096 virtual_nexus=AcquirePixelCacheNexus(1);
3097 if (virtual_nexus == (NexusInfo **) NULL)
3099 if (virtual_nexus != (NexusInfo **) NULL)
3100 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3101 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3102 "UnableToGetCacheNexus","`%s'",image->filename);
3103 return((const Quantum *) NULL);
3105 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3106 sizeof(*virtual_pixel));
3107 virtual_metacontent=(void *) NULL;
3108 switch (virtual_pixel_method)
3110 case BackgroundVirtualPixelMethod:
3111 case BlackVirtualPixelMethod:
3112 case GrayVirtualPixelMethod:
3113 case TransparentVirtualPixelMethod:
3114 case MaskVirtualPixelMethod:
3115 case WhiteVirtualPixelMethod:
3116 case EdgeVirtualPixelMethod:
3117 case CheckerTileVirtualPixelMethod:
3118 case HorizontalTileVirtualPixelMethod:
3119 case VerticalTileVirtualPixelMethod:
3121 if (cache_info->metacontent_extent != 0)
3124 Acquire a metacontent buffer.
3126 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3127 cache_info->metacontent_extent);
3128 if (virtual_metacontent == (void *) NULL)
3130 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3131 (void) ThrowMagickException(exception,GetMagickModule(),
3132 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3133 return((const Quantum *) NULL);
3135 (void) ResetMagickMemory(virtual_metacontent,0,
3136 cache_info->metacontent_extent);
3138 switch (virtual_pixel_method)
3140 case BlackVirtualPixelMethod:
3142 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3143 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3144 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3147 case GrayVirtualPixelMethod:
3149 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3150 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3152 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3155 case TransparentVirtualPixelMethod:
3157 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3158 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3159 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3162 case MaskVirtualPixelMethod:
3163 case WhiteVirtualPixelMethod:
3165 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3166 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3167 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3172 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3174 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3176 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3178 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3180 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3190 for (v=0; v < (ssize_t) rows; v++)
3192 for (u=0; u < (ssize_t) columns; u+=length)
3194 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3195 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3196 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3204 Transfer a single pixel.
3206 length=(MagickSizeType) 1;
3207 switch (virtual_pixel_method)
3211 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3212 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3213 1UL,1UL,*virtual_nexus,exception);
3214 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3217 case RandomVirtualPixelMethod:
3219 if (cache_info->random_info == (RandomInfo *) NULL)
3220 cache_info->random_info=AcquireRandomInfo();
3221 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3222 RandomX(cache_info->random_info,cache_info->columns),
3223 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3224 *virtual_nexus,exception);
3225 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3228 case DitherVirtualPixelMethod:
3230 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3231 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3232 1UL,1UL,*virtual_nexus,exception);
3233 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3236 case TileVirtualPixelMethod:
3238 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3239 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3240 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3241 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3243 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3246 case MirrorVirtualPixelMethod:
3248 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3249 if ((x_modulo.quotient & 0x01) == 1L)
3250 x_modulo.remainder=(ssize_t) cache_info->columns-
3251 x_modulo.remainder-1L;
3252 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3253 if ((y_modulo.quotient & 0x01) == 1L)
3254 y_modulo.remainder=(ssize_t) cache_info->rows-
3255 y_modulo.remainder-1L;
3256 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3257 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3259 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3262 case HorizontalTileEdgeVirtualPixelMethod:
3264 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3265 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3266 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3267 *virtual_nexus,exception);
3268 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3271 case VerticalTileEdgeVirtualPixelMethod:
3273 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3274 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3275 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3276 *virtual_nexus,exception);
3277 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3280 case BackgroundVirtualPixelMethod:
3281 case BlackVirtualPixelMethod:
3282 case GrayVirtualPixelMethod:
3283 case TransparentVirtualPixelMethod:
3284 case MaskVirtualPixelMethod:
3285 case WhiteVirtualPixelMethod:
3288 r=virtual_metacontent;
3291 case EdgeVirtualPixelMethod:
3292 case CheckerTileVirtualPixelMethod:
3294 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3295 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3296 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3299 r=virtual_metacontent;
3302 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3303 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3305 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3308 case HorizontalTileVirtualPixelMethod:
3310 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3313 r=virtual_metacontent;
3316 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3317 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3318 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3319 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3321 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3324 case VerticalTileVirtualPixelMethod:
3326 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3329 r=virtual_metacontent;
3332 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3333 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3334 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3335 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3337 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3341 if (p == (const Quantum *) NULL)
3343 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3345 q+=cache_info->number_channels;
3346 if ((s != (void *) NULL) && (r != (const void *) NULL))
3348 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3349 s+=cache_info->metacontent_extent;
3354 Transfer a run of pixels.
3356 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3357 length,1UL,*virtual_nexus,exception);
3358 if (p == (const Quantum *) NULL)
3360 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3361 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3362 q+=length*cache_info->number_channels;
3363 if ((r != (void *) NULL) && (s != (const void *) NULL))
3365 (void) memcpy(s,r,(size_t) length);
3366 s+=length*cache_info->metacontent_extent;
3373 if (virtual_metacontent != (void *) NULL)
3374 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3375 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3384 + G e t V i r t u a l P i x e l C a c h e %
3388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3390 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3391 % cache as defined by the geometry parameters. A pointer to the pixels
3392 % is returned if the pixels are transferred, otherwise a NULL is returned.
3394 % The format of the GetVirtualPixelCache() method is:
3396 % const Quantum *GetVirtualPixelCache(const Image *image,
3397 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3398 % const ssize_t y,const size_t columns,const size_t rows,
3399 % ExceptionInfo *exception)
3401 % A description of each parameter follows:
3403 % o image: the image.
3405 % o virtual_pixel_method: the virtual pixel method.
3407 % o x,y,columns,rows: These values define the perimeter of a region of
3410 % o exception: return any errors or warnings in this structure.
3413 static const Quantum *GetVirtualPixelCache(const Image *image,
3414 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3415 const size_t columns,const size_t rows,ExceptionInfo *exception)
3421 id = GetOpenMPThreadId();
3426 assert(image != (const Image *) NULL);
3427 assert(image->signature == MagickSignature);
3428 assert(image->cache != (Cache) NULL);
3429 cache_info=(CacheInfo *) image->cache;
3430 assert(cache_info->signature == MagickSignature);
3431 assert(id < (int) cache_info->number_threads);
3432 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3433 cache_info->nexus_info[id],exception);
3438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3442 % G e t V i r t u a l P i x e l Q u e u e %
3446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3448 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3449 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3451 % The format of the GetVirtualPixelQueue() method is:
3453 % const Quantum *GetVirtualPixelQueue(const Image image)
3455 % A description of each parameter follows:
3457 % o image: the image.
3460 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3466 id = GetOpenMPThreadId();
3468 assert(image != (const Image *) NULL);
3469 assert(image->signature == MagickSignature);
3470 assert(image->cache != (Cache) NULL);
3471 cache_info=(CacheInfo *) image->cache;
3472 assert(cache_info->signature == MagickSignature);
3473 if (cache_info->methods.get_virtual_pixels_handler !=
3474 (GetVirtualPixelsHandler) NULL)
3475 return(cache_info->methods.get_virtual_pixels_handler(image));
3476 assert(id < (int) cache_info->number_threads);
3477 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3485 % G e t V i r t u a l P i x e l s %
3489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3491 % GetVirtualPixels() returns an immutable pixel region. If the
3492 % region is successfully accessed, a pointer to it is returned, otherwise
3493 % NULL is returned. The returned pointer may point to a temporary working
3494 % copy of the pixels or it may point to the original pixels in memory.
3495 % Performance is maximized if the selected region is part of one row, or one
3496 % or more full rows, since there is opportunity to access the pixels in-place
3497 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3498 % returned pointer must *never* be deallocated by the user.
3500 % Pixels accessed via the returned pointer represent a simple array of type
3501 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3502 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3503 % access the meta-content (of type void) corresponding to the the
3506 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3508 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3509 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3510 % GetCacheViewAuthenticPixels() instead.
3512 % The format of the GetVirtualPixels() method is:
3514 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3515 % const ssize_t y,const size_t columns,const size_t rows,
3516 % ExceptionInfo *exception)
3518 % A description of each parameter follows:
3520 % o image: the image.
3522 % o x,y,columns,rows: These values define the perimeter of a region of
3525 % o exception: return any errors or warnings in this structure.
3528 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3529 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3530 ExceptionInfo *exception)
3536 id = GetOpenMPThreadId();
3541 assert(image != (const Image *) NULL);
3542 assert(image->signature == MagickSignature);
3543 assert(image->cache != (Cache) NULL);
3544 cache_info=(CacheInfo *) image->cache;
3545 assert(cache_info->signature == MagickSignature);
3546 if (cache_info->methods.get_virtual_pixel_handler !=
3547 (GetVirtualPixelHandler) NULL)
3548 return(cache_info->methods.get_virtual_pixel_handler(image,
3549 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3550 assert(id < (int) cache_info->number_threads);
3551 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3552 columns,rows,cache_info->nexus_info[id],exception);
3557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3561 + G e t V i r t u a l P i x e l s F r o m C a c h e %
3565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3567 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3568 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3570 % The format of the GetVirtualPixelsCache() method is:
3572 % Quantum *GetVirtualPixelsCache(const Image *image)
3574 % A description of each parameter follows:
3576 % o image: the image.
3579 static const Quantum *GetVirtualPixelsCache(const Image *image)
3585 id = GetOpenMPThreadId();
3587 assert(image != (const Image *) NULL);
3588 assert(image->signature == MagickSignature);
3589 assert(image->cache != (Cache) NULL);
3590 cache_info=(CacheInfo *) image->cache;
3591 assert(cache_info->signature == MagickSignature);
3592 assert(id < (int) cache_info->number_threads);
3593 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3601 + G e t V i r t u a l P i x e l s N e x u s %
3605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3607 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3610 % The format of the GetVirtualPixelsNexus() method is:
3612 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3613 % NexusInfo *nexus_info)
3615 % A description of each parameter follows:
3617 % o cache: the pixel cache.
3619 % o nexus_info: the cache nexus to return the colormap pixels.
3622 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3623 NexusInfo *nexus_info)
3628 assert(cache != (Cache) NULL);
3629 cache_info=(CacheInfo *) cache;
3630 assert(cache_info->signature == MagickSignature);
3631 if (cache_info->storage_class == UndefinedClass)
3632 return((Quantum *) NULL);
3633 return((const Quantum *) nexus_info->pixels);
3637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3641 + O p e n P i x e l C a c h e %
3645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3648 % dimensions, allocating space for the image pixels and optionally the
3649 % metacontent, and memory mapping the cache if it is disk based. The cache
3650 % nexus array is initialized as well.
3652 % The format of the OpenPixelCache() method is:
3654 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3655 % ExceptionInfo *exception)
3657 % A description of each parameter follows:
3659 % o image: the image.
3661 % o mode: ReadMode, WriteMode, or IOMode.
3663 % o exception: return any errors or warnings in this structure.
3667 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3669 cache_info->mapped=MagickFalse;
3670 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3671 cache_info->length);
3672 if (cache_info->pixels == (Quantum *) NULL)
3674 cache_info->mapped=MagickTrue;
3675 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3676 cache_info->length);
3680 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3690 cache_info=(CacheInfo *) image->cache;
3691 if (image->debug != MagickFalse)
3694 format[MaxTextExtent],
3695 message[MaxTextExtent];
3697 (void) FormatMagickSize(length,MagickFalse,format);
3698 (void) FormatLocaleString(message,MaxTextExtent,
3699 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3700 cache_info->cache_filename,cache_info->file,format);
3701 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3703 if (length != (MagickSizeType) ((MagickOffsetType) length))
3704 return(MagickFalse);
3705 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3707 return(MagickFalse);
3708 if ((MagickSizeType) extent >= length)
3710 offset=(MagickOffsetType) length-1;
3711 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3712 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3715 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3716 ExceptionInfo *exception)
3723 format[MaxTextExtent],
3724 message[MaxTextExtent];
3741 assert(image != (const Image *) NULL);
3742 assert(image->signature == MagickSignature);
3743 assert(image->cache != (Cache) NULL);
3744 if (image->debug != MagickFalse)
3745 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3746 if ((image->columns == 0) || (image->rows == 0))
3747 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3748 cache_info=(CacheInfo *) image->cache;
3749 assert(cache_info->signature == MagickSignature);
3750 source_info=(*cache_info);
3751 source_info.file=(-1);
3752 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3753 image->filename,(double) GetImageIndexInList(image));
3754 cache_info->storage_class=image->storage_class;
3755 cache_info->colorspace=image->colorspace;
3756 cache_info->matte=image->matte;
3757 cache_info->mask=image->mask;
3758 cache_info->rows=image->rows;
3759 cache_info->columns=image->columns;
3760 InitializePixelChannelMap(image);
3761 cache_info->number_channels=GetPixelChannels(image);
3762 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3763 sizeof(*image->channel_map));
3764 cache_info->metacontent_extent=image->metacontent_extent;
3765 cache_info->mode=mode;
3766 if (image->ping != MagickFalse)
3768 cache_info->type=PingCache;
3769 cache_info->pixels=(Quantum *) NULL;
3770 cache_info->metacontent=(void *) NULL;
3771 cache_info->length=0;
3774 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3775 packet_size=cache_info->number_channels*sizeof(Quantum);
3776 if (image->metacontent_extent != 0)
3777 packet_size+=cache_info->metacontent_extent;
3778 length=number_pixels*packet_size;
3779 columns=(size_t) (length/cache_info->rows/packet_size);
3780 if (cache_info->columns != columns)
3781 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3783 cache_info->length=length;
3784 p=cache_info->channel_map;
3785 q=source_info.channel_map;
3786 if ((cache_info->type != UndefinedCache) &&
3787 (cache_info->columns <= source_info.columns) &&
3788 (cache_info->rows <= source_info.rows) &&
3789 (cache_info->number_channels <= source_info.number_channels) &&
3790 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
3791 (cache_info->metacontent_extent <= source_info.metacontent_extent))
3794 Inline pixel cache clone optimization.
3796 if ((cache_info->columns == source_info.columns) &&
3797 (cache_info->rows == source_info.rows) &&
3798 (cache_info->number_channels == source_info.number_channels) &&
3799 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
3800 (cache_info->metacontent_extent == source_info.metacontent_extent))
3802 return(ClonePixelCachePixels(cache_info,&source_info,exception));
3804 status=AcquireMagickResource(AreaResource,cache_info->length);
3805 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3806 cache_info->metacontent_extent);
3807 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3809 status=AcquireMagickResource(MemoryResource,cache_info->length);
3810 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3811 (cache_info->type == MemoryCache))
3813 AllocatePixelCachePixels(cache_info);
3814 if (cache_info->pixels == (Quantum *) NULL)
3815 cache_info->pixels=source_info.pixels;
3819 Create memory pixel cache.
3822 if (image->debug != MagickFalse)
3824 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3825 (void) FormatLocaleString(message,MaxTextExtent,
3826 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3827 cache_info->filename,cache_info->mapped != MagickFalse ?
3828 "anonymous" : "heap",(double) cache_info->columns,(double)
3829 cache_info->rows,(double) cache_info->number_channels,
3831 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3834 cache_info->type=MemoryCache;
3835 cache_info->metacontent=(void *) NULL;
3836 if (cache_info->metacontent_extent != 0)
3837 cache_info->metacontent=(void *) (cache_info->pixels+
3838 number_pixels*cache_info->number_channels);
3839 if ((source_info.storage_class != UndefinedClass) &&
3842 status=ClonePixelCachePixels(cache_info,&source_info,
3844 RelinquishPixelCachePixels(&source_info);
3849 RelinquishMagickResource(MemoryResource,cache_info->length);
3852 Create pixel cache on disk.
3854 status=AcquireMagickResource(DiskResource,cache_info->length);
3855 if (status == MagickFalse)
3857 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3858 "CacheResourcesExhausted","`%s'",image->filename);
3859 return(MagickFalse);
3861 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3863 (void) ClosePixelCacheOnDisk(cache_info);
3864 *cache_info->cache_filename='\0';
3866 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3868 RelinquishMagickResource(DiskResource,cache_info->length);
3869 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3871 return(MagickFalse);
3873 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3874 cache_info->length);
3875 if (status == MagickFalse)
3877 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3879 return(MagickFalse);
3881 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3882 cache_info->metacontent_extent);
3883 if (length != (MagickSizeType) ((size_t) length))
3884 cache_info->type=DiskCache;
3887 status=AcquireMagickResource(MapResource,cache_info->length);
3888 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3889 (cache_info->type != MemoryCache))
3890 cache_info->type=DiskCache;
3893 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3894 cache_info->offset,(size_t) cache_info->length);
3895 if (cache_info->pixels == (Quantum *) NULL)
3897 cache_info->type=DiskCache;
3898 cache_info->pixels=source_info.pixels;
3903 Create file-backed memory-mapped pixel cache.
3906 (void) ClosePixelCacheOnDisk(cache_info);
3907 cache_info->type=MapCache;
3908 cache_info->mapped=MagickTrue;
3909 cache_info->metacontent=(void *) NULL;
3910 if (cache_info->metacontent_extent != 0)
3911 cache_info->metacontent=(void *) (cache_info->pixels+
3912 number_pixels*cache_info->number_channels);
3913 if ((source_info.storage_class != UndefinedClass) &&
3916 status=ClonePixelCachePixels(cache_info,&source_info,
3918 RelinquishPixelCachePixels(&source_info);
3920 if (image->debug != MagickFalse)
3922 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3923 (void) FormatLocaleString(message,MaxTextExtent,
3924 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
3925 cache_info->filename,cache_info->cache_filename,
3926 cache_info->file,(double) cache_info->columns,(double)
3927 cache_info->rows,(double) cache_info->number_channels,
3929 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3935 RelinquishMagickResource(MapResource,cache_info->length);
3938 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3940 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3941 RelinquishPixelCachePixels(&source_info);
3943 if (image->debug != MagickFalse)
3945 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3946 (void) FormatLocaleString(message,MaxTextExtent,
3947 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
3948 cache_info->cache_filename,cache_info->file,(double)
3949 cache_info->columns,(double) cache_info->rows,(double)
3950 cache_info->number_channels,format);
3951 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3961 + P e r s i s t P i x e l C a c h e %
3965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3967 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3968 % persistent pixel cache is one that resides on disk and is not destroyed
3969 % when the program exits.
3971 % The format of the PersistPixelCache() method is:
3973 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3974 % const MagickBooleanType attach,MagickOffsetType *offset,
3975 % ExceptionInfo *exception)
3977 % A description of each parameter follows:
3979 % o image: the image.
3981 % o filename: the persistent pixel cache filename.
3983 % o attach: A value other than zero initializes the persistent pixel cache.
3985 % o initialize: A value other than zero initializes the persistent pixel
3988 % o offset: the offset in the persistent cache to store pixels.
3990 % o exception: return any errors or warnings in this structure.
3993 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3994 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3995 ExceptionInfo *exception)
4010 assert(image != (Image *) NULL);
4011 assert(image->signature == MagickSignature);
4012 if (image->debug != MagickFalse)
4013 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4014 assert(image->cache != (void *) NULL);
4015 assert(filename != (const char *) NULL);
4016 assert(offset != (MagickOffsetType *) NULL);
4017 page_size=GetMagickPageSize();
4018 cache_info=(CacheInfo *) image->cache;
4019 assert(cache_info->signature == MagickSignature);
4020 if (attach != MagickFalse)
4023 Attach existing persistent pixel cache.
4025 if (image->debug != MagickFalse)
4026 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4027 "attach persistent cache");
4028 (void) CopyMagickString(cache_info->cache_filename,filename,
4030 cache_info->type=DiskCache;
4031 cache_info->offset=(*offset);
4032 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4033 return(MagickFalse);
4034 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4037 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4038 (cache_info->reference_count == 1))
4040 LockSemaphoreInfo(cache_info->semaphore);
4041 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4042 (cache_info->reference_count == 1))
4048 Usurp existing persistent pixel cache.
4050 status=rename_utf8(cache_info->cache_filename,filename);
4053 (void) CopyMagickString(cache_info->cache_filename,filename,
4055 *offset+=cache_info->length+page_size-(cache_info->length %
4057 UnlockSemaphoreInfo(cache_info->semaphore);
4058 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4059 if (image->debug != MagickFalse)
4060 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4061 "Usurp resident persistent cache");
4065 UnlockSemaphoreInfo(cache_info->semaphore);
4068 Clone persistent pixel cache.
4070 clone_image=(*image);
4071 clone_info=(CacheInfo *) clone_image.cache;
4072 image->cache=ClonePixelCache(cache_info);
4073 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4074 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4075 cache_info->type=DiskCache;
4076 cache_info->offset=(*offset);
4077 cache_info=(CacheInfo *) image->cache;
4078 status=OpenPixelCache(image,IOMode,exception);
4079 if (status != MagickFalse)
4080 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4081 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4082 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4087 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4091 + 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 %
4095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4097 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4098 % defined by the region rectangle and returns a pointer to the region. This
4099 % region is subsequently transferred from the pixel cache with
4100 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4101 % pixels are transferred, otherwise a NULL is returned.
4103 % The format of the QueueAuthenticPixelCacheNexus() method is:
4105 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4106 % const ssize_t y,const size_t columns,const size_t rows,
4107 % const MagickBooleanType clone,NexusInfo *nexus_info,
4108 % ExceptionInfo *exception)
4110 % A description of each parameter follows:
4112 % o image: the image.
4114 % o x,y,columns,rows: These values define the perimeter of a region of
4117 % o nexus_info: the cache nexus to set.
4119 % o clone: clone the pixel cache.
4121 % o exception: return any errors or warnings in this structure.
4124 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4125 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4126 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4141 Validate pixel cache geometry.
4143 assert(image != (const Image *) NULL);
4144 assert(image->signature == MagickSignature);
4145 assert(image->cache != (Cache) NULL);
4146 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4147 if (cache_info == (Cache) NULL)
4148 return((Quantum *) NULL);
4149 assert(cache_info->signature == MagickSignature);
4150 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4152 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4153 "NoPixelsDefinedInCache","`%s'",image->filename);
4154 return((Quantum *) NULL);
4156 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4157 (y >= (ssize_t) cache_info->rows))
4159 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4160 "PixelsAreNotAuthentic","`%s'",image->filename);
4161 return((Quantum *) NULL);
4163 offset=(MagickOffsetType) y*cache_info->columns+x;
4165 return((Quantum *) NULL);
4166 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4167 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4168 if ((MagickSizeType) offset >= number_pixels)
4169 return((Quantum *) NULL);
4175 region.width=columns;
4177 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4185 + 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 %
4189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4191 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4192 % defined by the region rectangle and returns a pointer to the region. This
4193 % region is subsequently transferred from the pixel cache with
4194 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4195 % pixels are transferred, otherwise a NULL is returned.
4197 % The format of the QueueAuthenticPixelsCache() method is:
4199 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4200 % const ssize_t y,const size_t columns,const size_t rows,
4201 % ExceptionInfo *exception)
4203 % A description of each parameter follows:
4205 % o image: the image.
4207 % o x,y,columns,rows: These values define the perimeter of a region of
4210 % o exception: return any errors or warnings in this structure.
4213 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4214 const ssize_t y,const size_t columns,const size_t rows,
4215 ExceptionInfo *exception)
4221 id = GetOpenMPThreadId();
4226 assert(image != (const Image *) NULL);
4227 assert(image->signature == MagickSignature);
4228 assert(image->cache != (Cache) NULL);
4229 cache_info=(CacheInfo *) image->cache;
4230 assert(cache_info->signature == MagickSignature);
4231 assert(id < (int) cache_info->number_threads);
4232 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4233 cache_info->nexus_info[id],exception);
4238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4242 % Q u e u e A u t h e n t i c P i x e l s %
4246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4248 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4249 % successfully initialized a pointer to a Quantum array representing the
4250 % region is returned, otherwise NULL is returned. The returned pointer may
4251 % point to a temporary working buffer for the pixels or it may point to the
4252 % final location of the pixels in memory.
4254 % Write-only access means that any existing pixel values corresponding to
4255 % the region are ignored. This is useful if the initial image is being
4256 % created from scratch, or if the existing pixel values are to be
4257 % completely replaced without need to refer to their pre-existing values.
4258 % The application is free to read and write the pixel buffer returned by
4259 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4260 % initialize the pixel array values. Initializing pixel array values is the
4261 % application's responsibility.
4263 % Performance is maximized if the selected region is part of one row, or
4264 % one or more full rows, since then there is opportunity to access the
4265 % pixels in-place (without a copy) if the image is in memory, or in a
4266 % memory-mapped file. The returned pointer must *never* be deallocated
4269 % Pixels accessed via the returned pointer represent a simple array of type
4270 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4271 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4272 % obtain the meta-content (of type void) corresponding to the region.
4273 % Once the Quantum (and/or Quantum) array has been updated, the
4274 % changes must be saved back to the underlying image using
4275 % SyncAuthenticPixels() or they may be lost.
4277 % The format of the QueueAuthenticPixels() method is:
4279 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4280 % const ssize_t y,const size_t columns,const size_t rows,
4281 % ExceptionInfo *exception)
4283 % A description of each parameter follows:
4285 % o image: the image.
4287 % o x,y,columns,rows: These values define the perimeter of a region of
4290 % o exception: return any errors or warnings in this structure.
4293 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4294 const ssize_t y,const size_t columns,const size_t rows,
4295 ExceptionInfo *exception)
4301 id = GetOpenMPThreadId();
4306 assert(image != (Image *) NULL);
4307 assert(image->signature == MagickSignature);
4308 assert(image->cache != (Cache) NULL);
4309 cache_info=(CacheInfo *) image->cache;
4310 assert(cache_info->signature == MagickSignature);
4311 if (cache_info->methods.queue_authentic_pixels_handler !=
4312 (QueueAuthenticPixelsHandler) NULL)
4314 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4318 assert(id < (int) cache_info->number_threads);
4319 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4320 cache_info->nexus_info[id],exception);
4325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4329 + 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 %
4333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4335 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4338 % The format of the ReadPixelCacheMetacontent() method is:
4340 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4341 % NexusInfo *nexus_info,ExceptionInfo *exception)
4343 % A description of each parameter follows:
4345 % o cache_info: the pixel cache.
4347 % o nexus_info: the cache nexus to read the metacontent.
4349 % o exception: return any errors or warnings in this structure.
4352 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4353 NexusInfo *nexus_info,ExceptionInfo *exception)
4366 register unsigned char
4372 if (cache_info->metacontent_extent == 0)
4373 return(MagickFalse);
4374 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4376 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4377 nexus_info->region.x;
4378 length=(MagickSizeType) nexus_info->region.width*
4379 cache_info->metacontent_extent;
4380 rows=nexus_info->region.height;
4382 q=(unsigned char *) nexus_info->metacontent;
4383 switch (cache_info->type)
4388 register unsigned char
4392 Read meta-content from memory.
4394 if ((cache_info->columns == nexus_info->region.width) &&
4395 (extent == (MagickSizeType) ((size_t) extent)))
4400 p=(unsigned char *) cache_info->metacontent+offset*
4401 cache_info->metacontent_extent;
4402 for (y=0; y < (ssize_t) rows; y++)
4404 (void) memcpy(q,p,(size_t) length);
4405 p+=cache_info->metacontent_extent*cache_info->columns;
4406 q+=cache_info->metacontent_extent*nexus_info->region.width;
4413 Read meta content from disk.
4415 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4417 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4418 cache_info->cache_filename);
4419 return(MagickFalse);
4421 if ((cache_info->columns == nexus_info->region.width) &&
4422 (extent <= MagickMaxBufferExtent))
4427 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4428 for (y=0; y < (ssize_t) rows; y++)
4430 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4431 cache_info->number_channels*sizeof(Quantum)+offset*
4432 cache_info->metacontent_extent,length,(unsigned char *) q);
4433 if ((MagickSizeType) count != length)
4435 offset+=cache_info->columns;
4436 q+=cache_info->metacontent_extent*nexus_info->region.width;
4438 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4439 (void) ClosePixelCacheOnDisk(cache_info);
4440 if (y < (ssize_t) rows)
4442 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4443 cache_info->cache_filename);
4444 return(MagickFalse);
4451 if ((cache_info->debug != MagickFalse) &&
4452 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4453 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4454 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4455 nexus_info->region.width,(double) nexus_info->region.height,(double)
4456 nexus_info->region.x,(double) nexus_info->region.y);
4461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4465 + R e a d P i x e l C a c h e P i x e l s %
4469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4471 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4474 % The format of the ReadPixelCachePixels() method is:
4476 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4477 % NexusInfo *nexus_info,ExceptionInfo *exception)
4479 % A description of each parameter follows:
4481 % o cache_info: the pixel cache.
4483 % o nexus_info: the cache nexus to read the pixels.
4485 % o exception: return any errors or warnings in this structure.
4488 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4489 NexusInfo *nexus_info,ExceptionInfo *exception)
4508 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4510 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4511 nexus_info->region.x;
4512 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4514 rows=nexus_info->region.height;
4516 q=nexus_info->pixels;
4517 switch (cache_info->type)
4526 Read pixels from memory.
4528 if ((cache_info->columns == nexus_info->region.width) &&
4529 (extent == (MagickSizeType) ((size_t) extent)))
4534 p=cache_info->pixels+offset*cache_info->number_channels;
4535 for (y=0; y < (ssize_t) rows; y++)
4537 (void) memcpy(q,p,(size_t) length);
4538 p+=cache_info->number_channels*cache_info->columns;
4539 q+=cache_info->number_channels*nexus_info->region.width;
4546 Read pixels from disk.
4548 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4550 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4551 cache_info->cache_filename);
4552 return(MagickFalse);
4554 if ((cache_info->columns == nexus_info->region.width) &&
4555 (extent <= MagickMaxBufferExtent))
4560 for (y=0; y < (ssize_t) rows; y++)
4562 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4563 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4564 if ((MagickSizeType) count != length)
4566 offset+=cache_info->columns;
4567 q+=cache_info->number_channels*nexus_info->region.width;
4569 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4570 (void) ClosePixelCacheOnDisk(cache_info);
4571 if (y < (ssize_t) rows)
4573 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4574 cache_info->cache_filename);
4575 return(MagickFalse);
4582 if ((cache_info->debug != MagickFalse) &&
4583 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4584 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4585 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4586 nexus_info->region.width,(double) nexus_info->region.height,(double)
4587 nexus_info->region.x,(double) nexus_info->region.y);
4592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4596 + R e f e r e n c e P i x e l C a c h e %
4600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4602 % ReferencePixelCache() increments the reference count associated with the
4603 % pixel cache returning a pointer to the cache.
4605 % The format of the ReferencePixelCache method is:
4607 % Cache ReferencePixelCache(Cache cache_info)
4609 % A description of each parameter follows:
4611 % o cache_info: the pixel cache.
4614 MagickPrivate Cache ReferencePixelCache(Cache cache)
4619 assert(cache != (Cache *) NULL);
4620 cache_info=(CacheInfo *) cache;
4621 assert(cache_info->signature == MagickSignature);
4622 LockSemaphoreInfo(cache_info->semaphore);
4623 cache_info->reference_count++;
4624 UnlockSemaphoreInfo(cache_info->semaphore);
4629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4633 + S e t P i x e l C a c h e M e t h o d s %
4637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4639 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4641 % The format of the SetPixelCacheMethods() method is:
4643 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4645 % A description of each parameter follows:
4647 % o cache: the pixel cache.
4649 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4652 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4657 GetOneAuthenticPixelFromHandler
4658 get_one_authentic_pixel_from_handler;
4660 GetOneVirtualPixelFromHandler
4661 get_one_virtual_pixel_from_handler;
4664 Set cache pixel methods.
4666 assert(cache != (Cache) NULL);
4667 assert(cache_methods != (CacheMethods *) NULL);
4668 cache_info=(CacheInfo *) cache;
4669 assert(cache_info->signature == MagickSignature);
4670 if (cache_info->debug != MagickFalse)
4671 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4672 cache_info->filename);
4673 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4674 cache_info->methods.get_virtual_pixel_handler=
4675 cache_methods->get_virtual_pixel_handler;
4676 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4677 cache_info->methods.destroy_pixel_handler=
4678 cache_methods->destroy_pixel_handler;
4679 if (cache_methods->get_virtual_metacontent_from_handler !=
4680 (GetVirtualMetacontentFromHandler) NULL)
4681 cache_info->methods.get_virtual_metacontent_from_handler=
4682 cache_methods->get_virtual_metacontent_from_handler;
4683 if (cache_methods->get_authentic_pixels_handler !=
4684 (GetAuthenticPixelsHandler) NULL)
4685 cache_info->methods.get_authentic_pixels_handler=
4686 cache_methods->get_authentic_pixels_handler;
4687 if (cache_methods->queue_authentic_pixels_handler !=
4688 (QueueAuthenticPixelsHandler) NULL)
4689 cache_info->methods.queue_authentic_pixels_handler=
4690 cache_methods->queue_authentic_pixels_handler;
4691 if (cache_methods->sync_authentic_pixels_handler !=
4692 (SyncAuthenticPixelsHandler) NULL)
4693 cache_info->methods.sync_authentic_pixels_handler=
4694 cache_methods->sync_authentic_pixels_handler;
4695 if (cache_methods->get_authentic_pixels_from_handler !=
4696 (GetAuthenticPixelsFromHandler) NULL)
4697 cache_info->methods.get_authentic_pixels_from_handler=
4698 cache_methods->get_authentic_pixels_from_handler;
4699 if (cache_methods->get_authentic_metacontent_from_handler !=
4700 (GetAuthenticMetacontentFromHandler) NULL)
4701 cache_info->methods.get_authentic_metacontent_from_handler=
4702 cache_methods->get_authentic_metacontent_from_handler;
4703 get_one_virtual_pixel_from_handler=
4704 cache_info->methods.get_one_virtual_pixel_from_handler;
4705 if (get_one_virtual_pixel_from_handler !=
4706 (GetOneVirtualPixelFromHandler) NULL)
4707 cache_info->methods.get_one_virtual_pixel_from_handler=
4708 cache_methods->get_one_virtual_pixel_from_handler;
4709 get_one_authentic_pixel_from_handler=
4710 cache_methods->get_one_authentic_pixel_from_handler;
4711 if (get_one_authentic_pixel_from_handler !=
4712 (GetOneAuthenticPixelFromHandler) NULL)
4713 cache_info->methods.get_one_authentic_pixel_from_handler=
4714 cache_methods->get_one_authentic_pixel_from_handler;
4718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4722 + S e t P i x e l C a c h e N e x u s P i x e l s %
4726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4728 % SetPixelCacheNexusPixels() defines the region of the cache for the
4729 % specified cache nexus.
4731 % The format of the SetPixelCacheNexusPixels() method is:
4733 % Quantum SetPixelCacheNexusPixels(const Image *image,
4734 % const RectangleInfo *region,NexusInfo *nexus_info,
4735 % ExceptionInfo *exception)
4737 % A description of each parameter follows:
4739 % o image: the image.
4741 % o region: A pointer to the RectangleInfo structure that defines the
4742 % region of this particular cache nexus.
4744 % o nexus_info: the cache nexus to set.
4746 % o exception: return any errors or warnings in this structure.
4750 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4751 NexusInfo *nexus_info,ExceptionInfo *exception)
4753 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4754 return(MagickFalse);
4755 nexus_info->mapped=MagickFalse;
4756 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
4757 nexus_info->length);
4758 if (nexus_info->cache == (Quantum *) NULL)
4760 nexus_info->mapped=MagickTrue;
4761 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4762 nexus_info->length);
4764 if (nexus_info->cache == (Quantum *) NULL)
4766 (void) ThrowMagickException(exception,GetMagickModule(),
4767 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4768 cache_info->filename);
4769 return(MagickFalse);
4774 static Quantum *SetPixelCacheNexusPixels(const Image *image,
4775 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4787 cache_info=(CacheInfo *) image->cache;
4788 assert(cache_info->signature == MagickSignature);
4789 if (cache_info->type == UndefinedCache)
4790 return((Quantum *) NULL);
4791 nexus_info->region=(*region);
4792 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
4798 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4799 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4800 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4801 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4802 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4803 ((nexus_info->region.width == cache_info->columns) ||
4804 ((nexus_info->region.width % cache_info->columns) == 0)))))
4810 Pixels are accessed directly from memory.
4812 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4813 nexus_info->region.x;
4814 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4816 nexus_info->metacontent=(void *) NULL;
4817 if (cache_info->metacontent_extent != 0)
4818 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4819 offset*cache_info->metacontent_extent;
4820 return(nexus_info->pixels);
4824 Pixels are stored in a cache region until they are synced to the cache.
4826 number_pixels=(MagickSizeType) nexus_info->region.width*
4827 nexus_info->region.height;
4828 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4829 if (cache_info->metacontent_extent != 0)
4830 length+=number_pixels*cache_info->metacontent_extent;
4831 if (nexus_info->cache == (Quantum *) NULL)
4833 nexus_info->length=length;
4834 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4835 if (status == MagickFalse)
4837 nexus_info->length=0;
4838 return((Quantum *) NULL);
4842 if (nexus_info->length != length)
4844 RelinquishCacheNexusPixels(nexus_info);
4845 nexus_info->length=length;
4846 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4847 if (status == MagickFalse)
4849 nexus_info->length=0;
4850 return((Quantum *) NULL);
4853 nexus_info->pixels=nexus_info->cache;
4854 nexus_info->metacontent=(void *) NULL;
4855 if (cache_info->metacontent_extent != 0)
4856 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4857 cache_info->number_channels);
4858 return(nexus_info->pixels);
4862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4866 % 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 %
4870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4872 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4873 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4874 % access that is outside the boundaries of the image cache.
4876 % The format of the SetPixelCacheVirtualMethod() method is:
4878 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4879 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4881 % A description of each parameter follows:
4883 % o image: the image.
4885 % o virtual_pixel_method: choose the type of virtual pixel.
4887 % o exception: return any errors or warnings in this structure.
4891 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4892 ExceptionInfo *exception)
4903 assert(image != (Image *) NULL);
4904 assert(image->signature == MagickSignature);
4905 if (image->debug != MagickFalse)
4906 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4907 assert(image->cache != (Cache) NULL);
4908 cache_info=(CacheInfo *) image->cache;
4909 assert(cache_info->signature == MagickSignature);
4910 image->matte=MagickTrue;
4912 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4913 #pragma omp parallel for schedule(static,4) shared(status)
4915 for (y=0; y < (ssize_t) image->rows; y++)
4918 id = GetOpenMPThreadId();
4926 if (status == MagickFalse)
4928 q=GetAuthenticPixelCacheNexus(image,0,y,image->columns,1,
4929 cache_info->nexus_info[id],exception);
4930 if (q == (Quantum *) NULL)
4935 for (x=0; x < (ssize_t) image->columns; x++)
4937 SetPixelAlpha(image,alpha,q);
4938 q+=GetPixelChannels(image);
4940 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4946 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4947 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4955 assert(image != (Image *) NULL);
4956 assert(image->signature == MagickSignature);
4957 if (image->debug != MagickFalse)
4958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4959 assert(image->cache != (Cache) NULL);
4960 cache_info=(CacheInfo *) image->cache;
4961 assert(cache_info->signature == MagickSignature);
4962 method=cache_info->virtual_pixel_method;
4963 cache_info->virtual_pixel_method=virtual_pixel_method;
4964 switch (virtual_pixel_method)
4966 case BackgroundVirtualPixelMethod:
4968 if ((image->background_color.matte != MagickFalse) &&
4969 (image->matte == MagickFalse))
4970 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4973 case TransparentVirtualPixelMethod:
4975 if (image->matte == MagickFalse)
4976 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4990 + 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 %
4994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4996 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4997 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4998 % is synced, otherwise MagickFalse.
5000 % The format of the SyncAuthenticPixelCacheNexus() method is:
5002 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5003 % NexusInfo *nexus_info,ExceptionInfo *exception)
5005 % A description of each parameter follows:
5007 % o image: the image.
5009 % o nexus_info: the cache nexus to sync.
5011 % o exception: return any errors or warnings in this structure.
5014 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5015 NexusInfo *nexus_info,ExceptionInfo *exception)
5024 Transfer pixels to the cache.
5026 assert(image != (Image *) NULL);
5027 assert(image->signature == MagickSignature);
5028 if (image->cache == (Cache) NULL)
5029 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5030 cache_info=(CacheInfo *) image->cache;
5031 assert(cache_info->signature == MagickSignature);
5032 if (cache_info->type == UndefinedCache)
5033 return(MagickFalse);
5034 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5036 assert(cache_info->signature == MagickSignature);
5037 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5038 if ((cache_info->metacontent_extent != 0) &&
5039 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5040 return(MagickFalse);
5045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5049 + S y n c A u t h e n t i c P i x e l C a c h e %
5053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5055 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5056 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5057 % otherwise MagickFalse.
5059 % The format of the SyncAuthenticPixelsCache() method is:
5061 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5062 % ExceptionInfo *exception)
5064 % A description of each parameter follows:
5066 % o image: the image.
5068 % o exception: return any errors or warnings in this structure.
5071 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5072 ExceptionInfo *exception)
5078 id = GetOpenMPThreadId();
5083 assert(image != (Image *) NULL);
5084 assert(image->signature == MagickSignature);
5085 assert(image->cache != (Cache) NULL);
5086 cache_info=(CacheInfo *) image->cache;
5087 assert(cache_info->signature == MagickSignature);
5088 assert(id < (int) cache_info->number_threads);
5089 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5099 % S y n c A u t h e n t i c P i x e l s %
5103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5105 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5106 % The method returns MagickTrue if the pixel region is flushed, otherwise
5109 % The format of the SyncAuthenticPixels() method is:
5111 % MagickBooleanType SyncAuthenticPixels(Image *image,
5112 % ExceptionInfo *exception)
5114 % A description of each parameter follows:
5116 % o image: the image.
5118 % o exception: return any errors or warnings in this structure.
5121 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5122 ExceptionInfo *exception)
5128 id = GetOpenMPThreadId();
5133 assert(image != (Image *) NULL);
5134 assert(image->signature == MagickSignature);
5135 assert(image->cache != (Cache) NULL);
5136 cache_info=(CacheInfo *) image->cache;
5137 assert(cache_info->signature == MagickSignature);
5138 if (cache_info->methods.sync_authentic_pixels_handler !=
5139 (SyncAuthenticPixelsHandler) NULL)
5141 status=cache_info->methods.sync_authentic_pixels_handler(image,
5145 assert(id < (int) cache_info->number_threads);
5146 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5156 + S y n c I m a g e P i x e l C a c h e %
5160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5162 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5163 % The method returns MagickTrue if the pixel region is flushed, otherwise
5166 % The format of the SyncImagePixelCache() method is:
5168 % MagickBooleanType SyncImagePixelCache(Image *image,
5169 % ExceptionInfo *exception)
5171 % A description of each parameter follows:
5173 % o image: the image.
5175 % o exception: return any errors or warnings in this structure.
5178 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5179 ExceptionInfo *exception)
5184 assert(image != (Image *) NULL);
5185 assert(exception != (ExceptionInfo *) NULL);
5186 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5187 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5195 + 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 %
5199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5201 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5202 % of the pixel cache.
5204 % The format of the WritePixelCacheMetacontent() method is:
5206 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5207 % NexusInfo *nexus_info,ExceptionInfo *exception)
5209 % A description of each parameter follows:
5211 % o cache_info: the pixel cache.
5213 % o nexus_info: the cache nexus to write the meta-content.
5215 % o exception: return any errors or warnings in this structure.
5218 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5219 NexusInfo *nexus_info,ExceptionInfo *exception)
5229 register const unsigned char
5238 if (cache_info->metacontent_extent == 0)
5239 return(MagickFalse);
5240 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5242 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5243 nexus_info->region.x;
5244 length=(MagickSizeType) nexus_info->region.width*
5245 cache_info->metacontent_extent;
5246 rows=nexus_info->region.height;
5247 extent=(MagickSizeType) length*rows;
5248 p=(unsigned char *) nexus_info->metacontent;
5249 switch (cache_info->type)
5254 register unsigned char
5258 Write associated pixels to memory.
5260 if ((cache_info->columns == nexus_info->region.width) &&
5261 (extent == (MagickSizeType) ((size_t) extent)))
5266 q=(unsigned char *) cache_info->metacontent+offset*
5267 cache_info->metacontent_extent;
5268 for (y=0; y < (ssize_t) rows; y++)
5270 (void) memcpy(q,p,(size_t) length);
5271 p+=nexus_info->region.width*cache_info->metacontent_extent;
5272 q+=cache_info->columns*cache_info->metacontent_extent;
5279 Write associated pixels to disk.
5281 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5283 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5284 cache_info->cache_filename);
5285 return(MagickFalse);
5287 if ((cache_info->columns == nexus_info->region.width) &&
5288 (extent <= MagickMaxBufferExtent))
5293 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5294 for (y=0; y < (ssize_t) rows; y++)
5296 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5297 cache_info->number_channels*sizeof(Quantum)+offset*
5298 cache_info->metacontent_extent,length,(const unsigned char *) p);
5299 if ((MagickSizeType) count != length)
5301 p+=nexus_info->region.width*cache_info->metacontent_extent;
5302 offset+=cache_info->columns;
5304 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5305 (void) ClosePixelCacheOnDisk(cache_info);
5306 if (y < (ssize_t) rows)
5308 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5309 cache_info->cache_filename);
5310 return(MagickFalse);
5317 if ((cache_info->debug != MagickFalse) &&
5318 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5319 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5320 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5321 nexus_info->region.width,(double) nexus_info->region.height,(double)
5322 nexus_info->region.x,(double) nexus_info->region.y);
5327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5331 + W r i t e C a c h e P i x e l s %
5335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5337 % WritePixelCachePixels() writes image pixels to the specified region of the
5340 % The format of the WritePixelCachePixels() method is:
5342 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5343 % NexusInfo *nexus_info,ExceptionInfo *exception)
5345 % A description of each parameter follows:
5347 % o cache_info: the pixel cache.
5349 % o nexus_info: the cache nexus to write the pixels.
5351 % o exception: return any errors or warnings in this structure.
5354 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5355 NexusInfo *nexus_info,ExceptionInfo *exception)
5365 register const Quantum
5374 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5376 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5377 nexus_info->region.x;
5378 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5380 rows=nexus_info->region.height;
5382 p=nexus_info->pixels;
5383 switch (cache_info->type)
5392 Write pixels to memory.
5394 if ((cache_info->columns == nexus_info->region.width) &&
5395 (extent == (MagickSizeType) ((size_t) extent)))
5400 q=cache_info->pixels+offset*cache_info->number_channels;
5401 for (y=0; y < (ssize_t) rows; y++)
5403 (void) memcpy(q,p,(size_t) length);
5404 p+=nexus_info->region.width*cache_info->number_channels;
5405 q+=cache_info->columns*cache_info->number_channels;
5412 Write pixels to disk.
5414 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5416 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5417 cache_info->cache_filename);
5418 return(MagickFalse);
5420 if ((cache_info->columns == nexus_info->region.width) &&
5421 (extent <= MagickMaxBufferExtent))
5426 for (y=0; y < (ssize_t) rows; y++)
5428 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5429 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5431 if ((MagickSizeType) count != length)
5433 p+=nexus_info->region.width*cache_info->number_channels;
5434 offset+=cache_info->columns;
5436 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5437 (void) ClosePixelCacheOnDisk(cache_info);
5438 if (y < (ssize_t) rows)
5440 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5441 cache_info->cache_filename);
5442 return(MagickFalse);
5449 if ((cache_info->debug != MagickFalse) &&
5450 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5451 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5452 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5453 nexus_info->region.width,(double) nexus_info->region.height,(double)
5454 nexus_info->region.x,(double) nexus_info->region.y);