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];
3737 assert(image != (const Image *) NULL);
3738 assert(image->signature == MagickSignature);
3739 assert(image->cache != (Cache) NULL);
3740 if (image->debug != MagickFalse)
3741 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3742 if ((image->columns == 0) || (image->rows == 0))
3743 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3744 cache_info=(CacheInfo *) image->cache;
3745 assert(cache_info->signature == MagickSignature);
3746 source_info=(*cache_info);
3747 source_info.file=(-1);
3748 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3749 image->filename,(double) GetImageIndexInList(image));
3750 cache_info->storage_class=image->storage_class;
3751 cache_info->colorspace=image->colorspace;
3752 cache_info->matte=image->matte;
3753 cache_info->mask=image->mask;
3754 cache_info->rows=image->rows;
3755 cache_info->columns=image->columns;
3756 InitializePixelChannelMap(image);
3757 cache_info->number_channels=GetPixelChannels(image);
3758 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3759 sizeof(*image->channel_map));
3760 cache_info->metacontent_extent=image->metacontent_extent;
3761 cache_info->mode=mode;
3762 if (image->ping != MagickFalse)
3764 cache_info->type=PingCache;
3765 cache_info->pixels=(Quantum *) NULL;
3766 cache_info->metacontent=(void *) NULL;
3767 cache_info->length=0;
3770 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3771 packet_size=cache_info->number_channels*sizeof(Quantum);
3772 if (image->metacontent_extent != 0)
3773 packet_size+=cache_info->metacontent_extent;
3774 length=number_pixels*packet_size;
3775 columns=(size_t) (length/cache_info->rows/packet_size);
3776 if (cache_info->columns != columns)
3777 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3779 cache_info->length=length;
3780 status=AcquireMagickResource(AreaResource,cache_info->length);
3781 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3782 cache_info->metacontent_extent);
3783 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3785 status=AcquireMagickResource(MemoryResource,cache_info->length);
3786 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3787 (cache_info->type == MemoryCache))
3789 AllocatePixelCachePixels(cache_info);
3790 if (cache_info->pixels == (Quantum *) NULL)
3791 cache_info->pixels=source_info.pixels;
3795 Create memory pixel cache.
3798 if (image->debug != MagickFalse)
3800 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3801 (void) FormatLocaleString(message,MaxTextExtent,
3802 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3803 cache_info->filename,cache_info->mapped != MagickFalse ?
3804 "anonymous" : "heap",(double) cache_info->columns,(double)
3805 cache_info->rows,(double) cache_info->number_channels,
3807 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3810 cache_info->type=MemoryCache;
3811 cache_info->metacontent=(void *) NULL;
3812 if (cache_info->metacontent_extent != 0)
3813 cache_info->metacontent=(void *) (cache_info->pixels+
3814 number_pixels*cache_info->number_channels);
3815 if ((source_info.storage_class != UndefinedClass) &&
3818 status=ClonePixelCachePixels(cache_info,&source_info,
3820 RelinquishPixelCachePixels(&source_info);
3825 RelinquishMagickResource(MemoryResource,cache_info->length);
3828 Create pixel cache on disk.
3830 status=AcquireMagickResource(DiskResource,cache_info->length);
3831 if (status == MagickFalse)
3833 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3834 "CacheResourcesExhausted","`%s'",image->filename);
3835 return(MagickFalse);
3837 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3839 (void) ClosePixelCacheOnDisk(cache_info);
3840 *cache_info->cache_filename='\0';
3842 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3844 RelinquishMagickResource(DiskResource,cache_info->length);
3845 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3847 return(MagickFalse);
3849 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3850 cache_info->length);
3851 if (status == MagickFalse)
3853 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3855 return(MagickFalse);
3857 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3858 cache_info->metacontent_extent);
3859 if (length != (MagickSizeType) ((size_t) length))
3860 cache_info->type=DiskCache;
3863 status=AcquireMagickResource(MapResource,cache_info->length);
3864 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3865 (cache_info->type != MemoryCache))
3866 cache_info->type=DiskCache;
3869 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3870 cache_info->offset,(size_t) cache_info->length);
3871 if (cache_info->pixels == (Quantum *) NULL)
3873 cache_info->type=DiskCache;
3874 cache_info->pixels=source_info.pixels;
3879 Create file-backed memory-mapped pixel cache.
3882 (void) ClosePixelCacheOnDisk(cache_info);
3883 cache_info->type=MapCache;
3884 cache_info->mapped=MagickTrue;
3885 cache_info->metacontent=(void *) NULL;
3886 if (cache_info->metacontent_extent != 0)
3887 cache_info->metacontent=(void *) (cache_info->pixels+
3888 number_pixels*cache_info->number_channels);
3889 if ((source_info.storage_class != UndefinedClass) &&
3892 status=ClonePixelCachePixels(cache_info,&source_info,
3894 RelinquishPixelCachePixels(&source_info);
3896 if (image->debug != MagickFalse)
3898 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3899 (void) FormatLocaleString(message,MaxTextExtent,
3900 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
3901 cache_info->filename,cache_info->cache_filename,
3902 cache_info->file,(double) cache_info->columns,(double)
3903 cache_info->rows,(double) cache_info->number_channels,
3905 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3911 RelinquishMagickResource(MapResource,cache_info->length);
3914 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3916 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3917 RelinquishPixelCachePixels(&source_info);
3919 if (image->debug != MagickFalse)
3921 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3922 (void) FormatLocaleString(message,MaxTextExtent,
3923 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
3924 cache_info->cache_filename,cache_info->file,(double)
3925 cache_info->columns,(double) cache_info->rows,(double)
3926 cache_info->number_channels,format);
3927 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3937 + P e r s i s t P i x e l C a c h e %
3941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3943 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3944 % persistent pixel cache is one that resides on disk and is not destroyed
3945 % when the program exits.
3947 % The format of the PersistPixelCache() method is:
3949 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3950 % const MagickBooleanType attach,MagickOffsetType *offset,
3951 % ExceptionInfo *exception)
3953 % A description of each parameter follows:
3955 % o image: the image.
3957 % o filename: the persistent pixel cache filename.
3959 % o attach: A value other than zero initializes the persistent pixel cache.
3961 % o initialize: A value other than zero initializes the persistent pixel
3964 % o offset: the offset in the persistent cache to store pixels.
3966 % o exception: return any errors or warnings in this structure.
3969 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3970 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3971 ExceptionInfo *exception)
3986 assert(image != (Image *) NULL);
3987 assert(image->signature == MagickSignature);
3988 if (image->debug != MagickFalse)
3989 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3990 assert(image->cache != (void *) NULL);
3991 assert(filename != (const char *) NULL);
3992 assert(offset != (MagickOffsetType *) NULL);
3993 page_size=GetMagickPageSize();
3994 cache_info=(CacheInfo *) image->cache;
3995 assert(cache_info->signature == MagickSignature);
3996 if (attach != MagickFalse)
3999 Attach existing persistent pixel cache.
4001 if (image->debug != MagickFalse)
4002 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4003 "attach persistent cache");
4004 (void) CopyMagickString(cache_info->cache_filename,filename,
4006 cache_info->type=DiskCache;
4007 cache_info->offset=(*offset);
4008 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4009 return(MagickFalse);
4010 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4013 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4014 (cache_info->reference_count == 1))
4016 LockSemaphoreInfo(cache_info->semaphore);
4017 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4018 (cache_info->reference_count == 1))
4024 Usurp existing persistent pixel cache.
4026 status=rename_utf8(cache_info->cache_filename,filename);
4029 (void) CopyMagickString(cache_info->cache_filename,filename,
4031 *offset+=cache_info->length+page_size-(cache_info->length %
4033 UnlockSemaphoreInfo(cache_info->semaphore);
4034 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4035 if (image->debug != MagickFalse)
4036 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4037 "Usurp resident persistent cache");
4041 UnlockSemaphoreInfo(cache_info->semaphore);
4044 Clone persistent pixel cache.
4046 clone_image=(*image);
4047 clone_info=(CacheInfo *) clone_image.cache;
4048 image->cache=ClonePixelCache(cache_info);
4049 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4050 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4051 cache_info->type=DiskCache;
4052 cache_info->offset=(*offset);
4053 cache_info=(CacheInfo *) image->cache;
4054 status=OpenPixelCache(image,IOMode,exception);
4055 if (status != MagickFalse)
4056 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4057 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4058 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4067 + 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 %
4071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4073 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4074 % defined by the region rectangle and returns a pointer to the region. This
4075 % region is subsequently transferred from the pixel cache with
4076 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4077 % pixels are transferred, otherwise a NULL is returned.
4079 % The format of the QueueAuthenticPixelCacheNexus() method is:
4081 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4082 % const ssize_t y,const size_t columns,const size_t rows,
4083 % const MagickBooleanType clone,NexusInfo *nexus_info,
4084 % ExceptionInfo *exception)
4086 % A description of each parameter follows:
4088 % o image: the image.
4090 % o x,y,columns,rows: These values define the perimeter of a region of
4093 % o nexus_info: the cache nexus to set.
4095 % o clone: clone the pixel cache.
4097 % o exception: return any errors or warnings in this structure.
4100 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4101 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4102 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4117 Validate pixel cache geometry.
4119 assert(image != (const Image *) NULL);
4120 assert(image->signature == MagickSignature);
4121 assert(image->cache != (Cache) NULL);
4122 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4123 if (cache_info == (Cache) NULL)
4124 return((Quantum *) NULL);
4125 assert(cache_info->signature == MagickSignature);
4126 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4128 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4129 "NoPixelsDefinedInCache","`%s'",image->filename);
4130 return((Quantum *) NULL);
4132 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4133 (y >= (ssize_t) cache_info->rows))
4135 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4136 "PixelsAreNotAuthentic","`%s'",image->filename);
4137 return((Quantum *) NULL);
4139 offset=(MagickOffsetType) y*cache_info->columns+x;
4141 return((Quantum *) NULL);
4142 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4143 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4144 if ((MagickSizeType) offset >= number_pixels)
4145 return((Quantum *) NULL);
4151 region.width=columns;
4153 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4161 + 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 %
4165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4167 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4168 % defined by the region rectangle and returns a pointer to the region. This
4169 % region is subsequently transferred from the pixel cache with
4170 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4171 % pixels are transferred, otherwise a NULL is returned.
4173 % The format of the QueueAuthenticPixelsCache() method is:
4175 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4176 % const ssize_t y,const size_t columns,const size_t rows,
4177 % ExceptionInfo *exception)
4179 % A description of each parameter follows:
4181 % o image: the image.
4183 % o x,y,columns,rows: These values define the perimeter of a region of
4186 % o exception: return any errors or warnings in this structure.
4189 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4190 const ssize_t y,const size_t columns,const size_t rows,
4191 ExceptionInfo *exception)
4197 id = GetOpenMPThreadId();
4202 assert(image != (const Image *) NULL);
4203 assert(image->signature == MagickSignature);
4204 assert(image->cache != (Cache) NULL);
4205 cache_info=(CacheInfo *) image->cache;
4206 assert(cache_info->signature == MagickSignature);
4207 assert(id < (int) cache_info->number_threads);
4208 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4209 cache_info->nexus_info[id],exception);
4214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4218 % Q u e u e A u t h e n t i c P i x e l s %
4222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4224 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4225 % successfully initialized a pointer to a Quantum array representing the
4226 % region is returned, otherwise NULL is returned. The returned pointer may
4227 % point to a temporary working buffer for the pixels or it may point to the
4228 % final location of the pixels in memory.
4230 % Write-only access means that any existing pixel values corresponding to
4231 % the region are ignored. This is useful if the initial image is being
4232 % created from scratch, or if the existing pixel values are to be
4233 % completely replaced without need to refer to their pre-existing values.
4234 % The application is free to read and write the pixel buffer returned by
4235 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4236 % initialize the pixel array values. Initializing pixel array values is the
4237 % application's responsibility.
4239 % Performance is maximized if the selected region is part of one row, or
4240 % one or more full rows, since then there is opportunity to access the
4241 % pixels in-place (without a copy) if the image is in memory, or in a
4242 % memory-mapped file. The returned pointer must *never* be deallocated
4245 % Pixels accessed via the returned pointer represent a simple array of type
4246 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4247 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4248 % obtain the meta-content (of type void) corresponding to the region.
4249 % Once the Quantum (and/or Quantum) array has been updated, the
4250 % changes must be saved back to the underlying image using
4251 % SyncAuthenticPixels() or they may be lost.
4253 % The format of the QueueAuthenticPixels() method is:
4255 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4256 % const ssize_t y,const size_t columns,const size_t rows,
4257 % ExceptionInfo *exception)
4259 % A description of each parameter follows:
4261 % o image: the image.
4263 % o x,y,columns,rows: These values define the perimeter of a region of
4266 % o exception: return any errors or warnings in this structure.
4269 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4270 const ssize_t y,const size_t columns,const size_t rows,
4271 ExceptionInfo *exception)
4277 id = GetOpenMPThreadId();
4282 assert(image != (Image *) NULL);
4283 assert(image->signature == MagickSignature);
4284 assert(image->cache != (Cache) NULL);
4285 cache_info=(CacheInfo *) image->cache;
4286 assert(cache_info->signature == MagickSignature);
4287 if (cache_info->methods.queue_authentic_pixels_handler !=
4288 (QueueAuthenticPixelsHandler) NULL)
4290 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4294 assert(id < (int) cache_info->number_threads);
4295 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4296 cache_info->nexus_info[id],exception);
4301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4305 + 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 %
4309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4311 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4314 % The format of the ReadPixelCacheMetacontent() method is:
4316 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4317 % NexusInfo *nexus_info,ExceptionInfo *exception)
4319 % A description of each parameter follows:
4321 % o cache_info: the pixel cache.
4323 % o nexus_info: the cache nexus to read the metacontent.
4325 % o exception: return any errors or warnings in this structure.
4328 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4329 NexusInfo *nexus_info,ExceptionInfo *exception)
4342 register unsigned char
4348 if (cache_info->metacontent_extent == 0)
4349 return(MagickFalse);
4350 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4352 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4353 nexus_info->region.x;
4354 length=(MagickSizeType) nexus_info->region.width*
4355 cache_info->metacontent_extent;
4356 rows=nexus_info->region.height;
4358 q=(unsigned char *) nexus_info->metacontent;
4359 switch (cache_info->type)
4364 register unsigned char
4368 Read meta-content from memory.
4370 if ((cache_info->columns == nexus_info->region.width) &&
4371 (extent == (MagickSizeType) ((size_t) extent)))
4376 p=(unsigned char *) cache_info->metacontent+offset*
4377 cache_info->metacontent_extent;
4378 for (y=0; y < (ssize_t) rows; y++)
4380 (void) memcpy(q,p,(size_t) length);
4381 p+=cache_info->metacontent_extent*cache_info->columns;
4382 q+=cache_info->metacontent_extent*nexus_info->region.width;
4389 Read meta content from disk.
4391 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4393 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4394 cache_info->cache_filename);
4395 return(MagickFalse);
4397 if ((cache_info->columns == nexus_info->region.width) &&
4398 (extent <= MagickMaxBufferExtent))
4403 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4404 for (y=0; y < (ssize_t) rows; y++)
4406 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4407 cache_info->number_channels*sizeof(Quantum)+offset*
4408 cache_info->metacontent_extent,length,(unsigned char *) q);
4409 if ((MagickSizeType) count != length)
4411 offset+=cache_info->columns;
4412 q+=cache_info->metacontent_extent*nexus_info->region.width;
4414 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4415 (void) ClosePixelCacheOnDisk(cache_info);
4416 if (y < (ssize_t) rows)
4418 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4419 cache_info->cache_filename);
4420 return(MagickFalse);
4427 if ((cache_info->debug != MagickFalse) &&
4428 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4429 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4430 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4431 nexus_info->region.width,(double) nexus_info->region.height,(double)
4432 nexus_info->region.x,(double) nexus_info->region.y);
4437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4441 + R e a d P i x e l C a c h e P i x e l s %
4445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4447 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4450 % The format of the ReadPixelCachePixels() method is:
4452 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4453 % NexusInfo *nexus_info,ExceptionInfo *exception)
4455 % A description of each parameter follows:
4457 % o cache_info: the pixel cache.
4459 % o nexus_info: the cache nexus to read the pixels.
4461 % o exception: return any errors or warnings in this structure.
4464 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4465 NexusInfo *nexus_info,ExceptionInfo *exception)
4484 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4486 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4487 nexus_info->region.x;
4488 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4490 rows=nexus_info->region.height;
4492 q=nexus_info->pixels;
4493 switch (cache_info->type)
4502 Read pixels from memory.
4504 if ((cache_info->columns == nexus_info->region.width) &&
4505 (extent == (MagickSizeType) ((size_t) extent)))
4510 p=cache_info->pixels+offset*cache_info->number_channels;
4511 for (y=0; y < (ssize_t) rows; y++)
4513 (void) memcpy(q,p,(size_t) length);
4514 p+=cache_info->number_channels*cache_info->columns;
4515 q+=cache_info->number_channels*nexus_info->region.width;
4522 Read pixels from disk.
4524 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4526 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4527 cache_info->cache_filename);
4528 return(MagickFalse);
4530 if ((cache_info->columns == nexus_info->region.width) &&
4531 (extent <= MagickMaxBufferExtent))
4536 for (y=0; y < (ssize_t) rows; y++)
4538 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4539 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4540 if ((MagickSizeType) count != length)
4542 offset+=cache_info->columns;
4543 q+=cache_info->number_channels*nexus_info->region.width;
4545 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4546 (void) ClosePixelCacheOnDisk(cache_info);
4547 if (y < (ssize_t) rows)
4549 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4550 cache_info->cache_filename);
4551 return(MagickFalse);
4558 if ((cache_info->debug != MagickFalse) &&
4559 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4560 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4561 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4562 nexus_info->region.width,(double) nexus_info->region.height,(double)
4563 nexus_info->region.x,(double) nexus_info->region.y);
4568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4572 + R e f e r e n c e P i x e l C a c h e %
4576 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4578 % ReferencePixelCache() increments the reference count associated with the
4579 % pixel cache returning a pointer to the cache.
4581 % The format of the ReferencePixelCache method is:
4583 % Cache ReferencePixelCache(Cache cache_info)
4585 % A description of each parameter follows:
4587 % o cache_info: the pixel cache.
4590 MagickPrivate Cache ReferencePixelCache(Cache cache)
4595 assert(cache != (Cache *) NULL);
4596 cache_info=(CacheInfo *) cache;
4597 assert(cache_info->signature == MagickSignature);
4598 LockSemaphoreInfo(cache_info->semaphore);
4599 cache_info->reference_count++;
4600 UnlockSemaphoreInfo(cache_info->semaphore);
4605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4609 + S e t P i x e l C a c h e M e t h o d s %
4613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4615 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4617 % The format of the SetPixelCacheMethods() method is:
4619 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4621 % A description of each parameter follows:
4623 % o cache: the pixel cache.
4625 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4628 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4633 GetOneAuthenticPixelFromHandler
4634 get_one_authentic_pixel_from_handler;
4636 GetOneVirtualPixelFromHandler
4637 get_one_virtual_pixel_from_handler;
4640 Set cache pixel methods.
4642 assert(cache != (Cache) NULL);
4643 assert(cache_methods != (CacheMethods *) NULL);
4644 cache_info=(CacheInfo *) cache;
4645 assert(cache_info->signature == MagickSignature);
4646 if (cache_info->debug != MagickFalse)
4647 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4648 cache_info->filename);
4649 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4650 cache_info->methods.get_virtual_pixel_handler=
4651 cache_methods->get_virtual_pixel_handler;
4652 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4653 cache_info->methods.destroy_pixel_handler=
4654 cache_methods->destroy_pixel_handler;
4655 if (cache_methods->get_virtual_metacontent_from_handler !=
4656 (GetVirtualMetacontentFromHandler) NULL)
4657 cache_info->methods.get_virtual_metacontent_from_handler=
4658 cache_methods->get_virtual_metacontent_from_handler;
4659 if (cache_methods->get_authentic_pixels_handler !=
4660 (GetAuthenticPixelsHandler) NULL)
4661 cache_info->methods.get_authentic_pixels_handler=
4662 cache_methods->get_authentic_pixels_handler;
4663 if (cache_methods->queue_authentic_pixels_handler !=
4664 (QueueAuthenticPixelsHandler) NULL)
4665 cache_info->methods.queue_authentic_pixels_handler=
4666 cache_methods->queue_authentic_pixels_handler;
4667 if (cache_methods->sync_authentic_pixels_handler !=
4668 (SyncAuthenticPixelsHandler) NULL)
4669 cache_info->methods.sync_authentic_pixels_handler=
4670 cache_methods->sync_authentic_pixels_handler;
4671 if (cache_methods->get_authentic_pixels_from_handler !=
4672 (GetAuthenticPixelsFromHandler) NULL)
4673 cache_info->methods.get_authentic_pixels_from_handler=
4674 cache_methods->get_authentic_pixels_from_handler;
4675 if (cache_methods->get_authentic_metacontent_from_handler !=
4676 (GetAuthenticMetacontentFromHandler) NULL)
4677 cache_info->methods.get_authentic_metacontent_from_handler=
4678 cache_methods->get_authentic_metacontent_from_handler;
4679 get_one_virtual_pixel_from_handler=
4680 cache_info->methods.get_one_virtual_pixel_from_handler;
4681 if (get_one_virtual_pixel_from_handler !=
4682 (GetOneVirtualPixelFromHandler) NULL)
4683 cache_info->methods.get_one_virtual_pixel_from_handler=
4684 cache_methods->get_one_virtual_pixel_from_handler;
4685 get_one_authentic_pixel_from_handler=
4686 cache_methods->get_one_authentic_pixel_from_handler;
4687 if (get_one_authentic_pixel_from_handler !=
4688 (GetOneAuthenticPixelFromHandler) NULL)
4689 cache_info->methods.get_one_authentic_pixel_from_handler=
4690 cache_methods->get_one_authentic_pixel_from_handler;
4694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4698 + S e t P i x e l C a c h e N e x u s P i x e l s %
4702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4704 % SetPixelCacheNexusPixels() defines the region of the cache for the
4705 % specified cache nexus.
4707 % The format of the SetPixelCacheNexusPixels() method is:
4709 % Quantum SetPixelCacheNexusPixels(const Image *image,
4710 % const RectangleInfo *region,NexusInfo *nexus_info,
4711 % ExceptionInfo *exception)
4713 % A description of each parameter follows:
4715 % o image: the image.
4717 % o region: A pointer to the RectangleInfo structure that defines the
4718 % region of this particular cache nexus.
4720 % o nexus_info: the cache nexus to set.
4722 % o exception: return any errors or warnings in this structure.
4726 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4727 NexusInfo *nexus_info,ExceptionInfo *exception)
4729 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4730 return(MagickFalse);
4731 nexus_info->mapped=MagickFalse;
4732 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
4733 nexus_info->length);
4734 if (nexus_info->cache == (Quantum *) NULL)
4736 nexus_info->mapped=MagickTrue;
4737 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4738 nexus_info->length);
4740 if (nexus_info->cache == (Quantum *) NULL)
4742 (void) ThrowMagickException(exception,GetMagickModule(),
4743 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4744 cache_info->filename);
4745 return(MagickFalse);
4750 static Quantum *SetPixelCacheNexusPixels(const Image *image,
4751 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4763 cache_info=(CacheInfo *) image->cache;
4764 assert(cache_info->signature == MagickSignature);
4765 if (cache_info->type == UndefinedCache)
4766 return((Quantum *) NULL);
4767 nexus_info->region=(*region);
4768 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
4774 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4775 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4776 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4777 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4778 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4779 ((nexus_info->region.width == cache_info->columns) ||
4780 ((nexus_info->region.width % cache_info->columns) == 0)))))
4786 Pixels are accessed directly from memory.
4788 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4789 nexus_info->region.x;
4790 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4792 nexus_info->metacontent=(void *) NULL;
4793 if (cache_info->metacontent_extent != 0)
4794 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4795 offset*cache_info->metacontent_extent;
4796 return(nexus_info->pixels);
4800 Pixels are stored in a cache region until they are synced to the cache.
4802 number_pixels=(MagickSizeType) nexus_info->region.width*
4803 nexus_info->region.height;
4804 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4805 if (cache_info->metacontent_extent != 0)
4806 length+=number_pixels*cache_info->metacontent_extent;
4807 if (nexus_info->cache == (Quantum *) NULL)
4809 nexus_info->length=length;
4810 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4811 if (status == MagickFalse)
4813 nexus_info->length=0;
4814 return((Quantum *) NULL);
4818 if (nexus_info->length != length)
4820 RelinquishCacheNexusPixels(nexus_info);
4821 nexus_info->length=length;
4822 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4823 if (status == MagickFalse)
4825 nexus_info->length=0;
4826 return((Quantum *) NULL);
4829 nexus_info->pixels=nexus_info->cache;
4830 nexus_info->metacontent=(void *) NULL;
4831 if (cache_info->metacontent_extent != 0)
4832 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4833 cache_info->number_channels);
4834 return(nexus_info->pixels);
4838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4842 % 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 %
4846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4848 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4849 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4850 % access that is outside the boundaries of the image cache.
4852 % The format of the SetPixelCacheVirtualMethod() method is:
4854 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4855 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4857 % A description of each parameter follows:
4859 % o image: the image.
4861 % o virtual_pixel_method: choose the type of virtual pixel.
4863 % o exception: return any errors or warnings in this structure.
4867 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4868 ExceptionInfo *exception)
4879 assert(image != (Image *) NULL);
4880 assert(image->signature == MagickSignature);
4881 if (image->debug != MagickFalse)
4882 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4883 assert(image->cache != (Cache) NULL);
4884 cache_info=(CacheInfo *) image->cache;
4885 assert(cache_info->signature == MagickSignature);
4886 image->matte=MagickTrue;
4888 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4889 #pragma omp parallel for schedule(static,4) shared(status)
4891 for (y=0; y < (ssize_t) image->rows; y++)
4894 id = GetOpenMPThreadId();
4902 if (status == MagickFalse)
4904 q=GetAuthenticPixelCacheNexus(image,0,y,image->columns,1,
4905 cache_info->nexus_info[id],exception);
4906 if (q == (Quantum *) NULL)
4911 for (x=0; x < (ssize_t) image->columns; x++)
4913 SetPixelAlpha(image,alpha,q);
4914 q+=GetPixelChannels(image);
4916 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4922 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4923 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4931 assert(image != (Image *) NULL);
4932 assert(image->signature == MagickSignature);
4933 if (image->debug != MagickFalse)
4934 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4935 assert(image->cache != (Cache) NULL);
4936 cache_info=(CacheInfo *) image->cache;
4937 assert(cache_info->signature == MagickSignature);
4938 method=cache_info->virtual_pixel_method;
4939 cache_info->virtual_pixel_method=virtual_pixel_method;
4940 switch (virtual_pixel_method)
4942 case BackgroundVirtualPixelMethod:
4944 if ((image->background_color.matte != MagickFalse) &&
4945 (image->matte == MagickFalse))
4946 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4949 case TransparentVirtualPixelMethod:
4951 if (image->matte == MagickFalse)
4952 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4966 + 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 %
4970 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4972 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4973 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4974 % is synced, otherwise MagickFalse.
4976 % The format of the SyncAuthenticPixelCacheNexus() method is:
4978 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4979 % NexusInfo *nexus_info,ExceptionInfo *exception)
4981 % A description of each parameter follows:
4983 % o image: the image.
4985 % o nexus_info: the cache nexus to sync.
4987 % o exception: return any errors or warnings in this structure.
4990 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4991 NexusInfo *nexus_info,ExceptionInfo *exception)
5000 Transfer pixels to the cache.
5002 assert(image != (Image *) NULL);
5003 assert(image->signature == MagickSignature);
5004 if (image->cache == (Cache) NULL)
5005 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5006 cache_info=(CacheInfo *) image->cache;
5007 assert(cache_info->signature == MagickSignature);
5008 if (cache_info->type == UndefinedCache)
5009 return(MagickFalse);
5010 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5012 assert(cache_info->signature == MagickSignature);
5013 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5014 if ((cache_info->metacontent_extent != 0) &&
5015 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5016 return(MagickFalse);
5021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5025 + S y n c A u t h e n t i c P i x e l C a c h e %
5029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5031 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5032 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5033 % otherwise MagickFalse.
5035 % The format of the SyncAuthenticPixelsCache() method is:
5037 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5038 % ExceptionInfo *exception)
5040 % A description of each parameter follows:
5042 % o image: the image.
5044 % o exception: return any errors or warnings in this structure.
5047 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5048 ExceptionInfo *exception)
5054 id = GetOpenMPThreadId();
5059 assert(image != (Image *) NULL);
5060 assert(image->signature == MagickSignature);
5061 assert(image->cache != (Cache) NULL);
5062 cache_info=(CacheInfo *) image->cache;
5063 assert(cache_info->signature == MagickSignature);
5064 assert(id < (int) cache_info->number_threads);
5065 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5075 % S y n c A u t h e n t i c P i x e l s %
5079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5081 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5082 % The method returns MagickTrue if the pixel region is flushed, otherwise
5085 % The format of the SyncAuthenticPixels() method is:
5087 % MagickBooleanType SyncAuthenticPixels(Image *image,
5088 % ExceptionInfo *exception)
5090 % A description of each parameter follows:
5092 % o image: the image.
5094 % o exception: return any errors or warnings in this structure.
5097 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5098 ExceptionInfo *exception)
5104 id = GetOpenMPThreadId();
5109 assert(image != (Image *) NULL);
5110 assert(image->signature == MagickSignature);
5111 assert(image->cache != (Cache) NULL);
5112 cache_info=(CacheInfo *) image->cache;
5113 assert(cache_info->signature == MagickSignature);
5114 if (cache_info->methods.sync_authentic_pixels_handler !=
5115 (SyncAuthenticPixelsHandler) NULL)
5117 status=cache_info->methods.sync_authentic_pixels_handler(image,
5121 assert(id < (int) cache_info->number_threads);
5122 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5132 + S y n c I m a g e P i x e l C a c h e %
5136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5138 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5139 % The method returns MagickTrue if the pixel region is flushed, otherwise
5142 % The format of the SyncImagePixelCache() method is:
5144 % MagickBooleanType SyncImagePixelCache(Image *image,
5145 % ExceptionInfo *exception)
5147 % A description of each parameter follows:
5149 % o image: the image.
5151 % o exception: return any errors or warnings in this structure.
5154 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5155 ExceptionInfo *exception)
5160 assert(image != (Image *) NULL);
5161 assert(exception != (ExceptionInfo *) NULL);
5162 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5163 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5171 + 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 %
5175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5177 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5178 % of the pixel cache.
5180 % The format of the WritePixelCacheMetacontent() method is:
5182 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5183 % NexusInfo *nexus_info,ExceptionInfo *exception)
5185 % A description of each parameter follows:
5187 % o cache_info: the pixel cache.
5189 % o nexus_info: the cache nexus to write the meta-content.
5191 % o exception: return any errors or warnings in this structure.
5194 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5195 NexusInfo *nexus_info,ExceptionInfo *exception)
5205 register const unsigned char
5214 if (cache_info->metacontent_extent == 0)
5215 return(MagickFalse);
5216 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5218 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5219 nexus_info->region.x;
5220 length=(MagickSizeType) nexus_info->region.width*
5221 cache_info->metacontent_extent;
5222 rows=nexus_info->region.height;
5223 extent=(MagickSizeType) length*rows;
5224 p=(unsigned char *) nexus_info->metacontent;
5225 switch (cache_info->type)
5230 register unsigned char
5234 Write associated pixels to memory.
5236 if ((cache_info->columns == nexus_info->region.width) &&
5237 (extent == (MagickSizeType) ((size_t) extent)))
5242 q=(unsigned char *) cache_info->metacontent+offset*
5243 cache_info->metacontent_extent;
5244 for (y=0; y < (ssize_t) rows; y++)
5246 (void) memcpy(q,p,(size_t) length);
5247 p+=nexus_info->region.width*cache_info->metacontent_extent;
5248 q+=cache_info->columns*cache_info->metacontent_extent;
5255 Write associated pixels to disk.
5257 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5259 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5260 cache_info->cache_filename);
5261 return(MagickFalse);
5263 if ((cache_info->columns == nexus_info->region.width) &&
5264 (extent <= MagickMaxBufferExtent))
5269 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5270 for (y=0; y < (ssize_t) rows; y++)
5272 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5273 cache_info->number_channels*sizeof(Quantum)+offset*
5274 cache_info->metacontent_extent,length,(const unsigned char *) p);
5275 if ((MagickSizeType) count != length)
5277 p+=nexus_info->region.width*cache_info->metacontent_extent;
5278 offset+=cache_info->columns;
5280 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5281 (void) ClosePixelCacheOnDisk(cache_info);
5282 if (y < (ssize_t) rows)
5284 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5285 cache_info->cache_filename);
5286 return(MagickFalse);
5293 if ((cache_info->debug != MagickFalse) &&
5294 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5295 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5296 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5297 nexus_info->region.width,(double) nexus_info->region.height,(double)
5298 nexus_info->region.x,(double) nexus_info->region.y);
5303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5307 + W r i t e C a c h e P i x e l s %
5311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5313 % WritePixelCachePixels() writes image pixels to the specified region of the
5316 % The format of the WritePixelCachePixels() method is:
5318 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5319 % NexusInfo *nexus_info,ExceptionInfo *exception)
5321 % A description of each parameter follows:
5323 % o cache_info: the pixel cache.
5325 % o nexus_info: the cache nexus to write the pixels.
5327 % o exception: return any errors or warnings in this structure.
5330 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5331 NexusInfo *nexus_info,ExceptionInfo *exception)
5341 register const Quantum
5350 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5352 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5353 nexus_info->region.x;
5354 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5356 rows=nexus_info->region.height;
5358 p=nexus_info->pixels;
5359 switch (cache_info->type)
5368 Write pixels to memory.
5370 if ((cache_info->columns == nexus_info->region.width) &&
5371 (extent == (MagickSizeType) ((size_t) extent)))
5376 q=cache_info->pixels+offset*cache_info->number_channels;
5377 for (y=0; y < (ssize_t) rows; y++)
5379 (void) memcpy(q,p,(size_t) length);
5380 p+=nexus_info->region.width*cache_info->number_channels;
5381 q+=cache_info->columns*cache_info->number_channels;
5388 Write pixels to disk.
5390 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5392 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5393 cache_info->cache_filename);
5394 return(MagickFalse);
5396 if ((cache_info->columns == nexus_info->region.width) &&
5397 (extent <= MagickMaxBufferExtent))
5402 for (y=0; y < (ssize_t) rows; y++)
5404 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5405 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5407 if ((MagickSizeType) count != length)
5409 p+=nexus_info->region.width*cache_info->number_channels;
5410 offset+=cache_info->columns;
5412 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5413 (void) ClosePixelCacheOnDisk(cache_info);
5414 if (y < (ssize_t) rows)
5416 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5417 cache_info->cache_filename);
5418 return(MagickFalse);
5425 if ((cache_info->debug != MagickFalse) &&
5426 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5427 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5428 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5429 nexus_info->region.width,(double) nexus_info->region.height,(double)
5430 nexus_info->region.x,(double) nexus_info->region.y);