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/memory-private.h"
58 #include "MagickCore/nt-base-private.h"
59 #include "MagickCore/pixel.h"
60 #include "MagickCore/pixel-accessor.h"
61 #include "MagickCore/policy.h"
62 #include "MagickCore/quantum.h"
63 #include "MagickCore/random_.h"
64 #include "MagickCore/resource_.h"
65 #include "MagickCore/semaphore.h"
66 #include "MagickCore/splay-tree.h"
67 #include "MagickCore/string_.h"
68 #include "MagickCore/string-private.h"
69 #include "MagickCore/thread-private.h"
70 #include "MagickCore/utility.h"
71 #include "MagickCore/utility-private.h"
72 #if defined(MAGICKCORE_ZLIB_DELEGATE)
79 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
80 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
81 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
86 typedef struct _MagickModulo
116 Forward declarations.
118 #if defined(__cplusplus) || defined(c_plusplus)
123 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
127 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
128 const ssize_t,const size_t,const size_t,ExceptionInfo *),
129 *GetVirtualPixelsCache(const Image *);
132 *GetVirtualMetacontentFromCache(const Image *);
134 static MagickBooleanType
135 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
137 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
138 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
139 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
140 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
141 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
142 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
143 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
144 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
147 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
148 const size_t,ExceptionInfo *),
149 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
150 const size_t,ExceptionInfo *),
151 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
152 NexusInfo *,ExceptionInfo *) magick_hot_spot;
154 #if defined(__cplusplus) || defined(c_plusplus)
161 static volatile MagickBooleanType
162 instantiate_cache = MagickFalse;
165 *cache_semaphore = (SemaphoreInfo *) NULL;
168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 + A c q u i r e P i x e l C a c h e %
176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
178 % AcquirePixelCache() acquires a pixel cache.
180 % The format of the AcquirePixelCache() method is:
182 % Cache AcquirePixelCache(const size_t number_threads)
184 % A description of each parameter follows:
186 % o number_threads: the number of nexus threads.
189 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
194 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
195 if (cache_info == (CacheInfo *) NULL)
196 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
197 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
198 cache_info->type=UndefinedCache;
199 cache_info->mode=IOMode;
200 cache_info->colorspace=sRGBColorspace;
201 cache_info->file=(-1);
202 cache_info->id=GetMagickThreadId();
203 cache_info->number_threads=number_threads;
204 if (number_threads == 0)
205 cache_info->number_threads=GetOpenMPMaximumThreads();
206 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
207 if (cache_info->nexus_info == (NexusInfo **) NULL)
208 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
209 cache_info->semaphore=AllocateSemaphoreInfo();
210 cache_info->reference_count=1;
211 cache_info->disk_semaphore=AllocateSemaphoreInfo();
212 cache_info->debug=IsEventLogging();
213 cache_info->signature=MagickSignature;
214 return((Cache ) cache_info);
218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222 % A c q u i r e P i x e l C a c h e N e x u s %
226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
230 % The format of the AcquirePixelCacheNexus method is:
232 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
234 % A description of each parameter follows:
236 % o number_threads: the number of nexus threads.
239 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
247 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
248 sizeof(*nexus_info));
249 if (nexus_info == (NexusInfo **) NULL)
250 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
251 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
252 sizeof(**nexus_info));
253 if (nexus_info[0] == (NexusInfo *) NULL)
254 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
255 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
256 for (i=0; i < (ssize_t) number_threads; i++)
258 nexus_info[i]=(&nexus_info[0][i]);
259 nexus_info[i]->signature=MagickSignature;
265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269 + A c q u i r e P i x e l C a c h e P i x e l s %
273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275 % AcquirePixelCachePixels() returns the pixels associated with the specified
278 % The format of the AcquirePixelCachePixels() method is:
280 % const void *AcquirePixelCachePixels(const Image *image,
281 % MagickSizeType *length,ExceptionInfo *exception)
283 % A description of each parameter follows:
285 % o image: the image.
287 % o length: the pixel cache length.
289 % o exception: return any errors or warnings in this structure.
292 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
293 MagickSizeType *length,ExceptionInfo *exception)
298 assert(image != (const Image *) NULL);
299 assert(image->signature == MagickSignature);
300 assert(exception != (ExceptionInfo *) NULL);
301 assert(exception->signature == MagickSignature);
302 assert(image->cache != (Cache) NULL);
303 cache_info=(CacheInfo *) image->cache;
304 assert(cache_info->signature == MagickSignature);
306 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
307 return((const void *) NULL);
308 *length=cache_info->length;
309 return((const void *) cache_info->pixels);
313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317 + C a c h e C o m p o n e n t G e n e s i s %
321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323 % CacheComponentGenesis() instantiates the cache component.
325 % The format of the CacheComponentGenesis method is:
327 % MagickBooleanType CacheComponentGenesis(void)
330 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
332 AcquireSemaphoreInfo(&cache_semaphore);
337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341 + C a c h e C o m p o n e n t T e r m i n u s %
345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347 % CacheComponentTerminus() destroys the cache component.
349 % The format of the CacheComponentTerminus() method is:
351 % CacheComponentTerminus(void)
354 MagickPrivate void CacheComponentTerminus(void)
356 if (cache_semaphore == (SemaphoreInfo *) NULL)
357 AcquireSemaphoreInfo(&cache_semaphore);
358 LockSemaphoreInfo(cache_semaphore);
359 instantiate_cache=MagickFalse;
360 UnlockSemaphoreInfo(cache_semaphore);
361 DestroySemaphoreInfo(&cache_semaphore);
365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
369 + C l o n e P i x e l C a c h e %
373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
375 % ClonePixelCache() clones a pixel cache.
377 % The format of the ClonePixelCache() method is:
379 % Cache ClonePixelCache(const Cache cache)
381 % A description of each parameter follows:
383 % o cache: the pixel cache.
386 MagickPrivate Cache ClonePixelCache(const Cache cache)
394 assert(cache != NULL);
395 cache_info=(const CacheInfo *) cache;
396 assert(cache_info->signature == MagickSignature);
397 if (cache_info->debug != MagickFalse)
398 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
399 cache_info->filename);
400 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
401 if (clone_info == (Cache) NULL)
402 return((Cache) NULL);
403 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
404 return((Cache ) clone_info);
408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412 + C l o n e P i x e l C a c h e P i x e l s %
416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
417 % ClonePixelCachePixels() clones the source pixel cache to the destination
420 % The format of the ClonePixelCachePixels() method is:
422 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
423 % CacheInfo *source_info,ExceptionInfo *exception)
425 % A description of each parameter follows:
427 % o cache_info: the pixel cache.
429 % o source_info: the source pixel cache.
431 % o exception: return any errors or warnings in this structure.
435 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
441 LockSemaphoreInfo(cache_info->disk_semaphore);
442 if (cache_info->file != -1)
444 status=close(cache_info->file);
445 cache_info->file=(-1);
446 RelinquishMagickResource(FileResource,1);
448 UnlockSemaphoreInfo(cache_info->disk_semaphore);
449 return(status == -1 ? MagickFalse : MagickTrue);
452 static inline MagickSizeType MagickMax(const MagickSizeType x,
453 const MagickSizeType y)
460 static inline MagickSizeType MagickMin(const MagickSizeType x,
461 const MagickSizeType y)
468 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
475 Open pixel cache on disk.
477 LockSemaphoreInfo(cache_info->disk_semaphore);
478 if (cache_info->file != -1)
480 UnlockSemaphoreInfo(cache_info->disk_semaphore);
481 return(MagickTrue); /* cache already open */
483 if (*cache_info->cache_filename == '\0')
484 file=AcquireUniqueFileResource(cache_info->cache_filename);
490 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
495 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
496 O_BINARY | O_EXCL,S_MODE);
498 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
504 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
507 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
513 UnlockSemaphoreInfo(cache_info->disk_semaphore);
516 (void) AcquireMagickResource(FileResource,1);
517 cache_info->file=file;
518 cache_info->mode=mode;
519 UnlockSemaphoreInfo(cache_info->disk_semaphore);
523 static inline MagickOffsetType ReadPixelCacheRegion(
524 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
525 const MagickSizeType length,unsigned char *restrict buffer)
527 register MagickOffsetType
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(
567 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
568 const MagickSizeType length,const unsigned char *restrict buffer)
570 register MagickOffsetType
576 #if !defined(MAGICKCORE_HAVE_PWRITE)
577 LockSemaphoreInfo(cache_info->disk_semaphore);
578 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
580 UnlockSemaphoreInfo(cache_info->disk_semaphore);
581 return((MagickOffsetType) -1);
585 for (i=0; i < (MagickOffsetType) length; i+=count)
587 #if !defined(MAGICKCORE_HAVE_PWRITE)
588 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
589 (MagickSizeType) SSIZE_MAX));
591 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
592 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
603 #if !defined(MAGICKCORE_HAVE_PWRITE)
604 UnlockSemaphoreInfo(cache_info->disk_semaphore);
609 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
610 CacheInfo *cache_info,ExceptionInfo *exception)
615 register MagickOffsetType
625 Clone pixel cache (both caches on disk).
627 if (cache_info->debug != MagickFalse)
628 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
629 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
631 if (blob == (unsigned char *) NULL)
633 (void) ThrowMagickException(exception,GetMagickModule(),
634 ResourceLimitError,"MemoryAllocationFailed","'%s'",
635 cache_info->filename);
638 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
640 blob=(unsigned char *) RelinquishMagickMemory(blob);
641 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
642 cache_info->cache_filename);
645 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
647 (void) ClosePixelCacheOnDisk(cache_info);
648 blob=(unsigned char *) RelinquishMagickMemory(blob);
649 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
650 clone_info->cache_filename);
654 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
656 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
657 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
661 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
662 cache_info->cache_filename);
665 length=(size_t) count;
666 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
667 if ((MagickSizeType) count != length)
669 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
670 clone_info->cache_filename);
674 (void) ClosePixelCacheOnDisk(clone_info);
675 (void) ClosePixelCacheOnDisk(cache_info);
676 blob=(unsigned char *) RelinquishMagickMemory(blob);
677 if (i < (MagickOffsetType) cache_info->length)
682 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
683 CacheInfo *cache_info,ExceptionInfo *exception)
688 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
691 Clone pixel cache (both caches in memory).
693 if (cache_info->debug != MagickFalse)
694 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
695 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
699 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
702 Clone pixel cache (one cache on disk, one in memory).
704 if (cache_info->debug != MagickFalse)
705 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
706 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
708 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
709 cache_info->cache_filename);
712 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
713 cache_info->length,(unsigned char *) clone_info->pixels);
714 (void) ClosePixelCacheOnDisk(cache_info);
715 if ((MagickSizeType) count != cache_info->length)
717 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
718 cache_info->cache_filename);
723 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
726 Clone pixel cache (one cache on disk, one in memory).
728 if (clone_info->debug != MagickFalse)
729 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
730 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
732 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
733 clone_info->cache_filename);
736 count=WritePixelCacheRegion(clone_info,clone_info->offset,
737 clone_info->length,(unsigned char *) cache_info->pixels);
738 (void) ClosePixelCacheOnDisk(clone_info);
739 if ((MagickSizeType) count != clone_info->length)
741 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
742 clone_info->cache_filename);
748 Clone pixel cache (both caches on disk).
750 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
753 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
754 CacheInfo *cache_info,ExceptionInfo *exception)
767 register unsigned char
780 Clone pixel cache (unoptimized).
782 if (cache_info->debug != MagickFalse)
784 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
787 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
790 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
793 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
795 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
796 clone_info->number_channels)*sizeof(Quantum),MagickMax(
797 cache_info->metacontent_extent,clone_info->metacontent_extent));
798 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
799 if (blob == (unsigned char *) NULL)
801 (void) ThrowMagickException(exception,GetMagickModule(),
802 ResourceLimitError,"MemoryAllocationFailed","'%s'",
803 cache_info->filename);
806 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
809 if (cache_info->type == DiskCache)
811 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
813 blob=(unsigned char *) RelinquishMagickMemory(blob);
814 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
815 cache_info->cache_filename);
818 cache_offset=cache_info->offset;
820 if (clone_info->type == DiskCache)
822 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
824 blob=(unsigned char *) RelinquishMagickMemory(blob);
825 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
826 clone_info->cache_filename);
829 clone_offset=clone_info->offset;
832 Clone pixel channels.
836 for (y=0; y < (ssize_t) cache_info->rows; y++)
838 for (x=0; x < (ssize_t) cache_info->columns; x++)
844 Read a set of pixel channels.
846 length=cache_info->number_channels*sizeof(Quantum);
847 if (cache_info->type != DiskCache)
848 p=(unsigned char *) cache_info->pixels+cache_offset;
851 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
852 if ((MagickSizeType) count != length)
858 cache_offset+=length;
859 if ((y < (ssize_t) clone_info->rows) &&
860 (x < (ssize_t) clone_info->columns))
861 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
873 Write a set of pixel channels.
875 channel=clone_info->channel_map[i].channel;
876 traits=cache_info->channel_map[channel].traits;
877 if (traits == UndefinedPixelTrait)
879 clone_offset+=sizeof(Quantum);
882 offset=cache_info->channel_map[channel].offset;
883 if (clone_info->type != DiskCache)
884 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
885 offset*sizeof(Quantum),sizeof(Quantum));
888 count=WritePixelCacheRegion(clone_info,clone_offset,
889 sizeof(Quantum),p+offset*sizeof(Quantum));
890 if ((MagickSizeType) count != sizeof(Quantum))
896 clone_offset+=sizeof(Quantum);
899 if (y < (ssize_t) clone_info->rows)
902 Set remaining columns as undefined.
904 length=clone_info->number_channels*sizeof(Quantum);
905 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
906 for ( ; x < (ssize_t) clone_info->columns; x++)
908 if (clone_info->type != DiskCache)
909 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
913 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
914 if ((MagickSizeType) count != length)
920 clone_offset+=length;
924 length=clone_info->number_channels*sizeof(Quantum);
925 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
926 for ( ; y < (ssize_t) clone_info->rows; y++)
929 Set remaining rows as undefined.
931 for (x=0; x < (ssize_t) clone_info->columns; x++)
933 if (clone_info->type != DiskCache)
934 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
938 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
939 if ((MagickSizeType) count != length)
945 clone_offset+=length;
948 if ((cache_info->metacontent_extent != 0) ||
949 (clone_info->metacontent_extent != 0))
954 for (y=0; y < (ssize_t) cache_info->rows; y++)
956 for (x=0; x < (ssize_t) cache_info->columns; x++)
959 Read a set of metacontent.
961 length=cache_info->metacontent_extent;
962 if (cache_info->type != DiskCache)
963 p=(unsigned char *) cache_info->pixels+cache_offset;
966 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
967 if ((MagickSizeType) count != length)
973 cache_offset+=length;
974 if ((y < (ssize_t) clone_info->rows) &&
975 (x < (ssize_t) clone_info->columns))
978 Write a set of metacontent.
980 length=clone_info->metacontent_extent;
981 if (clone_info->type != DiskCache)
982 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
986 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
987 if ((MagickSizeType) count != length)
993 clone_offset+=length;
996 length=clone_info->metacontent_extent;
997 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
998 for ( ; x < (ssize_t) clone_info->columns; x++)
1001 Set remaining columns as undefined.
1003 if (clone_info->type != DiskCache)
1004 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1008 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1009 if ((MagickSizeType) count != length)
1015 clone_offset+=length;
1018 if (y < (ssize_t) clone_info->rows)
1021 Set remaining rows as undefined.
1023 length=clone_info->metacontent_extent;
1024 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1025 for ( ; y < (ssize_t) clone_info->rows; y++)
1027 for (x=0; x < (ssize_t) clone_info->columns; x++)
1029 if (clone_info->type != DiskCache)
1030 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1034 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1036 if ((MagickSizeType) count != length)
1042 clone_offset+=length;
1047 if (clone_info->type == DiskCache)
1048 (void) ClosePixelCacheOnDisk(clone_info);
1049 if (cache_info->type == DiskCache)
1050 (void) ClosePixelCacheOnDisk(cache_info);
1051 blob=(unsigned char *) RelinquishMagickMemory(blob);
1055 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1056 CacheInfo *cache_info,ExceptionInfo *exception)
1062 if (cache_info->type == PingCache)
1064 p=cache_info->channel_map;
1065 q=clone_info->channel_map;
1066 if ((cache_info->columns == clone_info->columns) &&
1067 (cache_info->rows == clone_info->rows) &&
1068 (cache_info->number_channels == clone_info->number_channels) &&
1069 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1070 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1071 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1072 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1080 + C l o n e P i x e l C a c h e M e t h o d s %
1084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1089 % The format of the ClonePixelCacheMethods() method is:
1091 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1093 % A description of each parameter follows:
1095 % o clone: Specifies a pointer to a Cache structure.
1097 % o cache: the pixel cache.
1100 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1106 assert(clone != (Cache) NULL);
1107 source_info=(CacheInfo *) clone;
1108 assert(source_info->signature == MagickSignature);
1109 if (source_info->debug != MagickFalse)
1110 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1111 source_info->filename);
1112 assert(cache != (Cache) NULL);
1113 cache_info=(CacheInfo *) cache;
1114 assert(cache_info->signature == MagickSignature);
1115 source_info->methods=cache_info->methods;
1119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1123 + D e s t r o y I m a g e P i x e l C a c h e %
1127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1129 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1131 % The format of the DestroyImagePixelCache() method is:
1133 % void DestroyImagePixelCache(Image *image)
1135 % A description of each parameter follows:
1137 % o image: the image.
1140 static void DestroyImagePixelCache(Image *image)
1142 assert(image != (Image *) NULL);
1143 assert(image->signature == MagickSignature);
1144 if (image->debug != MagickFalse)
1145 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1146 if (image->cache == (void *) NULL)
1148 image->cache=DestroyPixelCache(image->cache);
1152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1156 + D e s t r o y I m a g e P i x e l s %
1160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1164 % The format of the DestroyImagePixels() method is:
1166 % void DestroyImagePixels(Image *image)
1168 % A description of each parameter follows:
1170 % o image: the image.
1173 MagickExport void DestroyImagePixels(Image *image)
1178 assert(image != (const Image *) NULL);
1179 assert(image->signature == MagickSignature);
1180 if (image->debug != MagickFalse)
1181 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1182 assert(image->cache != (Cache) NULL);
1183 cache_info=(CacheInfo *) image->cache;
1184 assert(cache_info->signature == MagickSignature);
1185 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1187 cache_info->methods.destroy_pixel_handler(image);
1190 image->cache=DestroyPixelCache(image->cache);
1194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198 + D e s t r o y P i x e l C a c h e %
1202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1204 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1206 % The format of the DestroyPixelCache() method is:
1208 % Cache DestroyPixelCache(Cache cache)
1210 % A description of each parameter follows:
1212 % o cache: the pixel cache.
1216 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1218 switch (cache_info->type)
1222 if (cache_info->mapped == MagickFalse)
1223 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
1224 cache_info->pixels);
1226 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1227 (size_t) cache_info->length);
1228 RelinquishMagickResource(MemoryResource,cache_info->length);
1233 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1234 cache_info->length);
1235 RelinquishMagickResource(MapResource,cache_info->length);
1239 if (cache_info->file != -1)
1240 (void) ClosePixelCacheOnDisk(cache_info);
1241 RelinquishMagickResource(DiskResource,cache_info->length);
1247 cache_info->type=UndefinedCache;
1248 cache_info->mapped=MagickFalse;
1249 cache_info->metacontent=(void *) NULL;
1252 MagickPrivate Cache DestroyPixelCache(Cache cache)
1257 assert(cache != (Cache) NULL);
1258 cache_info=(CacheInfo *) cache;
1259 assert(cache_info->signature == MagickSignature);
1260 if (cache_info->debug != MagickFalse)
1261 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1262 cache_info->filename);
1263 LockSemaphoreInfo(cache_info->semaphore);
1264 cache_info->reference_count--;
1265 if (cache_info->reference_count != 0)
1267 UnlockSemaphoreInfo(cache_info->semaphore);
1268 return((Cache) NULL);
1270 UnlockSemaphoreInfo(cache_info->semaphore);
1271 if (cache_info->debug != MagickFalse)
1274 message[MaxTextExtent];
1276 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1277 cache_info->filename);
1278 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1280 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1281 (cache_info->type != DiskCache)))
1282 RelinquishPixelCachePixels(cache_info);
1285 RelinquishPixelCachePixels(cache_info);
1286 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1288 *cache_info->cache_filename='\0';
1289 if (cache_info->nexus_info != (NexusInfo **) NULL)
1290 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1291 cache_info->number_threads);
1292 if (cache_info->random_info != (RandomInfo *) NULL)
1293 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1294 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1295 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1296 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1297 DestroySemaphoreInfo(&cache_info->semaphore);
1298 cache_info->signature=(~MagickSignature);
1299 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309 + D e s t r o y P i x e l C a c h e N e x u s %
1313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1315 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1317 % The format of the DestroyPixelCacheNexus() method is:
1319 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1320 % const size_t number_threads)
1322 % A description of each parameter follows:
1324 % o nexus_info: the nexus to destroy.
1326 % o number_threads: the number of nexus threads.
1330 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1332 if (nexus_info->mapped == MagickFalse)
1333 (void) RelinquishMagickMemory(nexus_info->cache);
1335 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1336 nexus_info->cache=(Quantum *) NULL;
1337 nexus_info->pixels=(Quantum *) NULL;
1338 nexus_info->metacontent=(void *) NULL;
1339 nexus_info->length=0;
1340 nexus_info->mapped=MagickFalse;
1343 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1344 const size_t number_threads)
1349 assert(nexus_info != (NexusInfo **) NULL);
1350 for (i=0; i < (ssize_t) number_threads; i++)
1352 if (nexus_info[i]->cache != (Quantum *) NULL)
1353 RelinquishCacheNexusPixels(nexus_info[i]);
1354 nexus_info[i]->signature=(~MagickSignature);
1356 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1357 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1366 % G e t A u t h e n t i c M e t a c o n t e n t %
1370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1372 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1373 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1374 % returned if the associated pixels are not available.
1376 % The format of the GetAuthenticMetacontent() method is:
1378 % void *GetAuthenticMetacontent(const Image *image)
1380 % A description of each parameter follows:
1382 % o image: the image.
1385 MagickExport void *GetAuthenticMetacontent(const Image *image)
1391 id = GetOpenMPThreadId();
1396 assert(image != (const Image *) NULL);
1397 assert(image->signature == MagickSignature);
1398 assert(image->cache != (Cache) NULL);
1399 cache_info=(CacheInfo *) image->cache;
1400 assert(cache_info->signature == MagickSignature);
1401 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1402 (GetAuthenticMetacontentFromHandler) NULL)
1404 metacontent=cache_info->methods.
1405 get_authentic_metacontent_from_handler(image);
1406 return(metacontent);
1408 assert(id < (int) cache_info->number_threads);
1409 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1410 cache_info->nexus_info[id]);
1411 return(metacontent);
1415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1419 + 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 %
1423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1425 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1426 % with the last call to QueueAuthenticPixelsCache() or
1427 % GetAuthenticPixelsCache().
1429 % The format of the GetAuthenticMetacontentFromCache() method is:
1431 % void *GetAuthenticMetacontentFromCache(const Image *image)
1433 % A description of each parameter follows:
1435 % o image: the image.
1438 static void *GetAuthenticMetacontentFromCache(const Image *image)
1444 id = GetOpenMPThreadId();
1449 assert(image != (const Image *) NULL);
1450 assert(image->signature == MagickSignature);
1451 assert(image->cache != (Cache) NULL);
1452 cache_info=(CacheInfo *) image->cache;
1453 assert(cache_info->signature == MagickSignature);
1454 assert(id < (int) cache_info->number_threads);
1455 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1456 cache_info->nexus_info[id]);
1457 return(metacontent);
1461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1465 + 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 %
1469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1471 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1472 % disk pixel cache as defined by the geometry parameters. A pointer to the
1473 % pixels is returned if the pixels are transferred, otherwise a NULL is
1476 % The format of the GetAuthenticPixelCacheNexus() method is:
1478 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1479 % const ssize_t y,const size_t columns,const size_t rows,
1480 % NexusInfo *nexus_info,ExceptionInfo *exception)
1482 % A description of each parameter follows:
1484 % o image: the image.
1486 % o x,y,columns,rows: These values define the perimeter of a region of
1489 % o nexus_info: the cache nexus to return.
1491 % o exception: return any errors or warnings in this structure.
1495 static inline MagickBooleanType IsPixelAuthentic(
1496 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1504 if (cache_info->type == PingCache)
1506 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1507 nexus_info->region.x;
1508 status=nexus_info->pixels == (cache_info->pixels+offset*
1509 cache_info->number_channels) ? MagickTrue : MagickFalse;
1513 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1514 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1515 NexusInfo *nexus_info,ExceptionInfo *exception)
1524 Transfer pixels from the cache.
1526 assert(image != (Image *) NULL);
1527 assert(image->signature == MagickSignature);
1528 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1530 if (q == (Quantum *) NULL)
1531 return((Quantum *) NULL);
1532 cache_info=(CacheInfo *) image->cache;
1533 assert(cache_info->signature == MagickSignature);
1534 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1536 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1537 return((Quantum *) NULL);
1538 if (cache_info->metacontent_extent != 0)
1539 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1540 return((Quantum *) NULL);
1545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1549 + 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 %
1553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1555 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1556 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1558 % The format of the GetAuthenticPixelsFromCache() method is:
1560 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1562 % A description of each parameter follows:
1564 % o image: the image.
1567 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1573 id = GetOpenMPThreadId();
1575 assert(image != (const Image *) NULL);
1576 assert(image->signature == MagickSignature);
1577 assert(image->cache != (Cache) NULL);
1578 cache_info=(CacheInfo *) image->cache;
1579 assert(cache_info->signature == MagickSignature);
1580 assert(id < (int) cache_info->number_threads);
1581 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589 % G e t A u t h e n t i c P i x e l Q u e u e %
1593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595 % GetAuthenticPixelQueue() returns the authentic pixels associated
1596 % corresponding with the last call to QueueAuthenticPixels() or
1597 % GetAuthenticPixels().
1599 % The format of the GetAuthenticPixelQueue() method is:
1601 % Quantum *GetAuthenticPixelQueue(const Image image)
1603 % A description of each parameter follows:
1605 % o image: the image.
1608 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1614 id = GetOpenMPThreadId();
1616 assert(image != (const Image *) NULL);
1617 assert(image->signature == MagickSignature);
1618 assert(image->cache != (Cache) NULL);
1619 cache_info=(CacheInfo *) image->cache;
1620 assert(cache_info->signature == MagickSignature);
1621 if (cache_info->methods.get_authentic_pixels_from_handler !=
1622 (GetAuthenticPixelsFromHandler) NULL)
1623 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1624 assert(id < (int) cache_info->number_threads);
1625 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 % G e t A u t h e n t i c P i x e l s %
1636 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1639 % region is successfully accessed, a pointer to a Quantum array
1640 % representing the region is returned, otherwise NULL is returned.
1642 % The returned pointer may point to a temporary working copy of the pixels
1643 % or it may point to the original pixels in memory. Performance is maximized
1644 % if the selected region is part of one row, or one or more full rows, since
1645 % then there is opportunity to access the pixels in-place (without a copy)
1646 % if the image is in memory, or in a memory-mapped file. The returned pointer
1647 % must *never* be deallocated by the user.
1649 % Pixels accessed via the returned pointer represent a simple array of type
1650 % Quantum. If the image has corresponding metacontent,call
1651 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1652 % meta-content corresponding to the region. Once the Quantum array has
1653 % been updated, the changes must be saved back to the underlying image using
1654 % SyncAuthenticPixels() or they may be lost.
1656 % The format of the GetAuthenticPixels() method is:
1658 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1659 % const ssize_t y,const size_t columns,const size_t rows,
1660 % ExceptionInfo *exception)
1662 % A description of each parameter follows:
1664 % o image: the image.
1666 % o x,y,columns,rows: These values define the perimeter of a region of
1669 % o exception: return any errors or warnings in this structure.
1672 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1673 const ssize_t y,const size_t columns,const size_t rows,
1674 ExceptionInfo *exception)
1680 id = GetOpenMPThreadId();
1685 assert(image != (Image *) NULL);
1686 assert(image->signature == MagickSignature);
1687 assert(image->cache != (Cache) NULL);
1688 cache_info=(CacheInfo *) image->cache;
1689 assert(cache_info->signature == MagickSignature);
1690 if (cache_info->methods.get_authentic_pixels_handler !=
1691 (GetAuthenticPixelsHandler) NULL)
1693 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1697 assert(id < (int) cache_info->number_threads);
1698 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1699 cache_info->nexus_info[id],exception);
1704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1708 + G e t A u t h e n t i c P i x e l s C a c h e %
1712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1714 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1715 % as defined by the geometry parameters. A pointer to the pixels is returned
1716 % if the pixels are transferred, otherwise a NULL is returned.
1718 % The format of the GetAuthenticPixelsCache() method is:
1720 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1721 % const ssize_t y,const size_t columns,const size_t rows,
1722 % ExceptionInfo *exception)
1724 % A description of each parameter follows:
1726 % o image: the image.
1728 % o x,y,columns,rows: These values define the perimeter of a region of
1731 % o exception: return any errors or warnings in this structure.
1734 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1735 const ssize_t y,const size_t columns,const size_t rows,
1736 ExceptionInfo *exception)
1742 id = GetOpenMPThreadId();
1747 assert(image != (const Image *) NULL);
1748 assert(image->signature == MagickSignature);
1749 assert(image->cache != (Cache) NULL);
1750 cache_info=(CacheInfo *) image->cache;
1751 if (cache_info == (Cache) NULL)
1752 return((Quantum *) NULL);
1753 assert(cache_info->signature == MagickSignature);
1754 assert(id < (int) cache_info->number_threads);
1755 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1756 cache_info->nexus_info[id],exception);
1761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765 + G e t I m a g e E x t e n t %
1769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1771 % GetImageExtent() returns the extent of the pixels associated corresponding
1772 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1774 % The format of the GetImageExtent() method is:
1776 % MagickSizeType GetImageExtent(const Image *image)
1778 % A description of each parameter follows:
1780 % o image: the image.
1783 MagickExport MagickSizeType GetImageExtent(const Image *image)
1789 id = GetOpenMPThreadId();
1791 assert(image != (Image *) NULL);
1792 assert(image->signature == MagickSignature);
1793 if (image->debug != MagickFalse)
1794 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1795 assert(image->cache != (Cache) NULL);
1796 cache_info=(CacheInfo *) image->cache;
1797 assert(cache_info->signature == MagickSignature);
1798 assert(id < (int) cache_info->number_threads);
1799 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1807 + G e t I m a g e P i x e l C a c h e %
1811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1813 % GetImagePixelCache() ensures that there is only a single reference to the
1814 % pixel cache to be modified, updating the provided cache pointer to point to
1815 % a clone of the original pixel cache if necessary.
1817 % The format of the GetImagePixelCache method is:
1819 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1820 % ExceptionInfo *exception)
1822 % A description of each parameter follows:
1824 % o image: the image.
1826 % o clone: any value other than MagickFalse clones the cache pixels.
1828 % o exception: return any errors or warnings in this structure.
1832 static inline MagickBooleanType ValidatePixelCacheMorphology(
1833 const Image *restrict image)
1836 *restrict cache_info;
1838 const PixelChannelMap
1843 Does the image match the pixel cache morphology?
1845 cache_info=(CacheInfo *) image->cache;
1846 p=image->channel_map;
1847 q=cache_info->channel_map;
1848 if ((image->storage_class != cache_info->storage_class) ||
1849 (image->colorspace != cache_info->colorspace) ||
1850 (image->matte != cache_info->matte) ||
1851 (image->mask != cache_info->mask) ||
1852 (image->columns != cache_info->columns) ||
1853 (image->rows != cache_info->rows) ||
1854 (image->number_channels != cache_info->number_channels) ||
1855 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1856 (image->metacontent_extent != cache_info->metacontent_extent) ||
1857 (cache_info->nexus_info == (NexusInfo **) NULL))
1858 return(MagickFalse);
1862 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1863 ExceptionInfo *exception)
1872 static MagickSizeType
1878 cache_timestamp = 0;
1881 LockSemaphoreInfo(image->semaphore);
1882 if (cpu_throttle == 0)
1888 Set CPU throttle in milleseconds.
1890 cpu_throttle=MagickResourceInfinity;
1891 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1892 if (limit == (char *) NULL)
1893 limit=GetPolicyValue("throttle");
1894 if (limit != (char *) NULL)
1896 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1897 limit=DestroyString(limit);
1900 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1901 MagickDelay(cpu_throttle);
1902 if (time_limit == 0)
1905 Set the exire time in seconds.
1907 time_limit=GetMagickResourceLimit(TimeResource);
1908 cache_timestamp=time((time_t *) NULL);
1910 if ((time_limit != MagickResourceInfinity) &&
1911 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1912 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1913 assert(image->cache != (Cache) NULL);
1914 cache_info=(CacheInfo *) image->cache;
1915 destroy=MagickFalse;
1916 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1918 LockSemaphoreInfo(cache_info->semaphore);
1919 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1930 clone_image=(*image);
1931 clone_image.semaphore=AllocateSemaphoreInfo();
1932 clone_image.reference_count=1;
1933 clone_image.cache=ClonePixelCache(cache_info);
1934 clone_info=(CacheInfo *) clone_image.cache;
1935 status=OpenPixelCache(&clone_image,IOMode,exception);
1936 if (status != MagickFalse)
1938 if (clone != MagickFalse)
1939 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1940 if (status != MagickFalse)
1942 if (cache_info->mode == ReadMode)
1943 cache_info->nexus_info=(NexusInfo **) NULL;
1945 image->cache=clone_image.cache;
1948 DestroySemaphoreInfo(&clone_image.semaphore);
1950 UnlockSemaphoreInfo(cache_info->semaphore);
1952 if (destroy != MagickFalse)
1953 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1954 if (status != MagickFalse)
1957 Ensure the image matches the pixel cache morphology.
1959 image->taint=MagickTrue;
1960 image->type=UndefinedType;
1961 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1963 status=OpenPixelCache(image,IOMode,exception);
1964 cache_info=(CacheInfo *) image->cache;
1965 if (cache_info->type == DiskCache)
1966 (void) ClosePixelCacheOnDisk(cache_info);
1969 UnlockSemaphoreInfo(image->semaphore);
1970 if (status == MagickFalse)
1971 return((Cache) NULL);
1972 return(image->cache);
1976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980 + G e t I m a g e P i x e l C a c h e T y p e %
1984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1986 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1987 % DiskCache, MemoryCache, MapCache, or PingCache.
1989 % The format of the GetImagePixelCacheType() method is:
1991 % CacheType GetImagePixelCacheType(const Image *image)
1993 % A description of each parameter follows:
1995 % o image: the image.
1998 MagickExport CacheType GetImagePixelCacheType(const Image *image)
2003 assert(image != (Image *) NULL);
2004 assert(image->signature == MagickSignature);
2005 assert(image->cache != (Cache) NULL);
2006 cache_info=(CacheInfo *) image->cache;
2007 assert(cache_info->signature == MagickSignature);
2008 return(cache_info->type);
2012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2016 % G e t O n e A u t h e n t i c P i x e l %
2020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2022 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2023 % location. The image background color is returned if an error occurs.
2025 % The format of the GetOneAuthenticPixel() method is:
2027 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2028 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2030 % A description of each parameter follows:
2032 % o image: the image.
2034 % o x,y: These values define the location of the pixel to return.
2036 % o pixel: return a pixel at the specified (x,y) location.
2038 % o exception: return any errors or warnings in this structure.
2041 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2042 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2053 assert(image != (Image *) NULL);
2054 assert(image->signature == MagickSignature);
2055 assert(image->cache != (Cache) NULL);
2056 cache_info=(CacheInfo *) image->cache;
2057 assert(cache_info->signature == MagickSignature);
2058 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2059 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2060 (GetOneAuthenticPixelFromHandler) NULL)
2061 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2063 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2064 if (q == (Quantum *) NULL)
2066 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2067 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2068 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2069 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2070 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2071 return(MagickFalse);
2073 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2078 channel=GetPixelChannelMapChannel(image,i);
2079 pixel[channel]=q[i];
2085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2089 + 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 %
2093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2095 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2096 % location. The image background color is returned if an error occurs.
2098 % The format of the GetOneAuthenticPixelFromCache() method is:
2100 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2101 % const ssize_t x,const ssize_t y,Quantum *pixel,
2102 % ExceptionInfo *exception)
2104 % A description of each parameter follows:
2106 % o image: the image.
2108 % o x,y: These values define the location of the pixel to return.
2110 % o pixel: return a pixel at the specified (x,y) location.
2112 % o exception: return any errors or warnings in this structure.
2115 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2116 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2122 id = GetOpenMPThreadId();
2130 assert(image != (const Image *) NULL);
2131 assert(image->signature == MagickSignature);
2132 assert(image->cache != (Cache) NULL);
2133 cache_info=(CacheInfo *) image->cache;
2134 assert(cache_info->signature == MagickSignature);
2135 assert(id < (int) cache_info->number_threads);
2136 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2137 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2139 if (q == (Quantum *) NULL)
2141 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2142 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2143 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2144 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2145 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2146 return(MagickFalse);
2148 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2153 channel=GetPixelChannelMapChannel(image,i);
2154 pixel[channel]=q[i];
2160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2164 % G e t O n e V i r t u a l P i x e l %
2168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2170 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2171 % (x,y) location. The image background color is returned if an error occurs.
2172 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2174 % The format of the GetOneVirtualPixel() method is:
2176 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2177 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2179 % A description of each parameter follows:
2181 % o image: the image.
2183 % o x,y: These values define the location of the pixel to return.
2185 % o pixel: return a pixel at the specified (x,y) location.
2187 % o exception: return any errors or warnings in this structure.
2190 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2191 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2197 id = GetOpenMPThreadId();
2205 assert(image != (const Image *) NULL);
2206 assert(image->signature == MagickSignature);
2207 assert(image->cache != (Cache) NULL);
2208 cache_info=(CacheInfo *) image->cache;
2209 assert(cache_info->signature == MagickSignature);
2210 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2211 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2212 (GetOneVirtualPixelFromHandler) NULL)
2213 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2214 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2215 assert(id < (int) cache_info->number_threads);
2216 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2217 1UL,1UL,cache_info->nexus_info[id],exception);
2218 if (p == (const Quantum *) NULL)
2220 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2221 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2222 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2223 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2224 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2225 return(MagickFalse);
2227 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2232 channel=GetPixelChannelMapChannel(image,i);
2233 pixel[channel]=p[i];
2239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243 + 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 %
2247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2249 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2250 % specified (x,y) location. The image background color is returned if an
2253 % The format of the GetOneVirtualPixelFromCache() method is:
2255 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2256 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2257 % Quantum *pixel,ExceptionInfo *exception)
2259 % A description of each parameter follows:
2261 % o image: the image.
2263 % o virtual_pixel_method: the virtual pixel method.
2265 % o x,y: These values define the location of the pixel to return.
2267 % o pixel: return a pixel at the specified (x,y) location.
2269 % o exception: return any errors or warnings in this structure.
2272 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2273 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2274 Quantum *pixel,ExceptionInfo *exception)
2280 id = GetOpenMPThreadId();
2288 assert(image != (const Image *) NULL);
2289 assert(image->signature == MagickSignature);
2290 assert(image->cache != (Cache) NULL);
2291 cache_info=(CacheInfo *) image->cache;
2292 assert(cache_info->signature == MagickSignature);
2293 assert(id < (int) cache_info->number_threads);
2294 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2295 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2296 cache_info->nexus_info[id],exception);
2297 if (p == (const Quantum *) NULL)
2299 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2300 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2301 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2302 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2303 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2304 return(MagickFalse);
2306 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2311 channel=GetPixelChannelMapChannel(image,i);
2312 pixel[channel]=p[i];
2318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2322 % G e t O n e V i r t u a l P i x e l I n f o %
2326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2328 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2329 % location. The image background color is returned if an error occurs. If
2330 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2332 % The format of the GetOneVirtualPixelInfo() method is:
2334 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2335 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2336 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2338 % A description of each parameter follows:
2340 % o image: the image.
2342 % o virtual_pixel_method: the virtual pixel method.
2344 % o x,y: these values define the location of the pixel to return.
2346 % o pixel: return a pixel at the specified (x,y) location.
2348 % o exception: return any errors or warnings in this structure.
2351 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2352 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2353 PixelInfo *pixel,ExceptionInfo *exception)
2359 id = GetOpenMPThreadId();
2361 register const Quantum
2364 assert(image != (const Image *) NULL);
2365 assert(image->signature == MagickSignature);
2366 assert(image->cache != (Cache) NULL);
2367 cache_info=(CacheInfo *) image->cache;
2368 assert(cache_info->signature == MagickSignature);
2369 assert(id < (int) cache_info->number_threads);
2370 GetPixelInfo(image,pixel);
2371 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2372 cache_info->nexus_info[id],exception);
2373 if (p == (const Quantum *) NULL)
2374 return(MagickFalse);
2375 GetPixelInfoPixel(image,p,pixel);
2380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2384 + G e t P i x e l C a c h e C o l o r s p a c e %
2388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2390 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2392 % The format of the GetPixelCacheColorspace() method is:
2394 % Colorspace GetPixelCacheColorspace(Cache cache)
2396 % A description of each parameter follows:
2398 % o cache: the pixel cache.
2401 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2406 assert(cache != (Cache) NULL);
2407 cache_info=(CacheInfo *) cache;
2408 assert(cache_info->signature == MagickSignature);
2409 if (cache_info->debug != MagickFalse)
2410 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2411 cache_info->filename);
2412 return(cache_info->colorspace);
2416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2420 + G e t P i x e l C a c h e M e t h o d s %
2424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2426 % GetPixelCacheMethods() initializes the CacheMethods structure.
2428 % The format of the GetPixelCacheMethods() method is:
2430 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2432 % A description of each parameter follows:
2434 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2437 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2439 assert(cache_methods != (CacheMethods *) NULL);
2440 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2441 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2442 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2443 cache_methods->get_virtual_metacontent_from_handler=
2444 GetVirtualMetacontentFromCache;
2445 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2446 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2447 cache_methods->get_authentic_metacontent_from_handler=
2448 GetAuthenticMetacontentFromCache;
2449 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2450 cache_methods->get_one_authentic_pixel_from_handler=
2451 GetOneAuthenticPixelFromCache;
2452 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2453 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2454 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2462 + G e t P i x e l C a c h e N e x u s E x t e n t %
2466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2468 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2469 % corresponding with the last call to SetPixelCacheNexusPixels() or
2470 % GetPixelCacheNexusPixels().
2472 % The format of the GetPixelCacheNexusExtent() method is:
2474 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2475 % NexusInfo *nexus_info)
2477 % A description of each parameter follows:
2479 % o nexus_info: the nexus info.
2482 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2483 NexusInfo *nexus_info)
2491 assert(cache != NULL);
2492 cache_info=(CacheInfo *) cache;
2493 assert(cache_info->signature == MagickSignature);
2494 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2496 return((MagickSizeType) cache_info->columns*cache_info->rows);
2501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2505 + 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 %
2509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2511 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2514 % The format of the GetPixelCacheNexusMetacontent() method is:
2516 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2517 % NexusInfo *nexus_info)
2519 % A description of each parameter follows:
2521 % o cache: the pixel cache.
2523 % o nexus_info: the cache nexus to return the meta-content.
2526 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2527 NexusInfo *nexus_info)
2532 assert(cache != NULL);
2533 cache_info=(CacheInfo *) cache;
2534 assert(cache_info->signature == MagickSignature);
2535 if (cache_info->storage_class == UndefinedClass)
2536 return((void *) NULL);
2537 return(nexus_info->metacontent);
2541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2545 + G e t P i x e l C a c h e N e x u s P i x e l s %
2549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2551 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2554 % The format of the GetPixelCacheNexusPixels() method is:
2556 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2557 % NexusInfo *nexus_info)
2559 % A description of each parameter follows:
2561 % o cache: the pixel cache.
2563 % o nexus_info: the cache nexus to return the pixels.
2566 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2567 NexusInfo *nexus_info)
2572 assert(cache != NULL);
2573 cache_info=(CacheInfo *) cache;
2574 assert(cache_info->signature == MagickSignature);
2575 if (cache_info->storage_class == UndefinedClass)
2576 return((Quantum *) NULL);
2577 return(nexus_info->pixels);
2581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2585 + G e t P i x e l C a c h e P i x e l s %
2589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591 % GetPixelCachePixels() returns the pixels associated with the specified image.
2593 % The format of the GetPixelCachePixels() method is:
2595 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2596 % ExceptionInfo *exception)
2598 % A description of each parameter follows:
2600 % o image: the image.
2602 % o length: the pixel cache length.
2604 % o exception: return any errors or warnings in this structure.
2607 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2608 ExceptionInfo *exception)
2613 assert(image != (const Image *) NULL);
2614 assert(image->signature == MagickSignature);
2615 assert(image->cache != (Cache) NULL);
2616 assert(length != (MagickSizeType *) NULL);
2617 assert(exception != (ExceptionInfo *) NULL);
2618 assert(exception->signature == MagickSignature);
2619 cache_info=(CacheInfo *) image->cache;
2620 assert(cache_info->signature == MagickSignature);
2622 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2623 return((void *) NULL);
2624 *length=cache_info->length;
2625 return((void *) cache_info->pixels);
2629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2633 + 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 %
2637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2639 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2641 % The format of the GetPixelCacheStorageClass() method is:
2643 % ClassType GetPixelCacheStorageClass(Cache cache)
2645 % A description of each parameter follows:
2647 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2649 % o cache: the pixel cache.
2652 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2657 assert(cache != (Cache) NULL);
2658 cache_info=(CacheInfo *) cache;
2659 assert(cache_info->signature == MagickSignature);
2660 if (cache_info->debug != MagickFalse)
2661 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2662 cache_info->filename);
2663 return(cache_info->storage_class);
2667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2671 + G e t P i x e l C a c h e T i l e S i z e %
2675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2677 % GetPixelCacheTileSize() returns the pixel cache tile size.
2679 % The format of the GetPixelCacheTileSize() method is:
2681 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2684 % A description of each parameter follows:
2686 % o image: the image.
2688 % o width: the optimize cache tile width in pixels.
2690 % o height: the optimize cache tile height in pixels.
2693 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2699 assert(image != (Image *) NULL);
2700 assert(image->signature == MagickSignature);
2701 if (image->debug != MagickFalse)
2702 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2703 cache_info=(CacheInfo *) image->cache;
2704 assert(cache_info->signature == MagickSignature);
2705 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2706 if (GetImagePixelCacheType(image) == DiskCache)
2707 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2716 + 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 %
2720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2722 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2723 % pixel cache. A virtual pixel is any pixel access that is outside the
2724 % boundaries of the image cache.
2726 % The format of the GetPixelCacheVirtualMethod() method is:
2728 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2730 % A description of each parameter follows:
2732 % o image: the image.
2735 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2740 assert(image != (Image *) NULL);
2741 assert(image->signature == MagickSignature);
2742 assert(image->cache != (Cache) NULL);
2743 cache_info=(CacheInfo *) image->cache;
2744 assert(cache_info->signature == MagickSignature);
2745 return(cache_info->virtual_pixel_method);
2749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2753 + 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 %
2757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2759 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2760 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2762 % The format of the GetVirtualMetacontentFromCache() method is:
2764 % void *GetVirtualMetacontentFromCache(const Image *image)
2766 % A description of each parameter follows:
2768 % o image: the image.
2771 static const void *GetVirtualMetacontentFromCache(const Image *image)
2777 id = GetOpenMPThreadId();
2782 assert(image != (const Image *) NULL);
2783 assert(image->signature == MagickSignature);
2784 assert(image->cache != (Cache) NULL);
2785 cache_info=(CacheInfo *) image->cache;
2786 assert(cache_info->signature == MagickSignature);
2787 assert(id < (int) cache_info->number_threads);
2788 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2789 cache_info->nexus_info[id]);
2790 return(metacontent);
2794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2798 + 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 %
2802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2807 % The format of the GetVirtualMetacontentFromNexus() method is:
2809 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2810 % NexusInfo *nexus_info)
2812 % A description of each parameter follows:
2814 % o cache: the pixel cache.
2816 % o nexus_info: the cache nexus to return the meta-content.
2819 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2820 NexusInfo *nexus_info)
2825 assert(cache != (Cache) NULL);
2826 cache_info=(CacheInfo *) cache;
2827 assert(cache_info->signature == MagickSignature);
2828 if (cache_info->storage_class == UndefinedClass)
2829 return((void *) NULL);
2830 return(nexus_info->metacontent);
2834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838 % G e t V i r t u a l M e t a c o n t e n t %
2842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2844 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2845 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2846 % returned if the meta-content are not available.
2848 % The format of the GetVirtualMetacontent() method is:
2850 % const void *GetVirtualMetacontent(const Image *image)
2852 % A description of each parameter follows:
2854 % o image: the image.
2857 MagickExport const void *GetVirtualMetacontent(const Image *image)
2863 id = GetOpenMPThreadId();
2868 assert(image != (const Image *) NULL);
2869 assert(image->signature == MagickSignature);
2870 assert(image->cache != (Cache) NULL);
2871 cache_info=(CacheInfo *) image->cache;
2872 assert(cache_info->signature == MagickSignature);
2873 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2874 if (metacontent != (void *) NULL)
2875 return(metacontent);
2876 assert(id < (int) cache_info->number_threads);
2877 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2878 cache_info->nexus_info[id]);
2879 return(metacontent);
2883 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2887 + 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 %
2891 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2893 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2894 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2895 % is returned if the pixels are transferred, otherwise a NULL is returned.
2897 % The format of the GetVirtualPixelsFromNexus() method is:
2899 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2900 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2901 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2902 % ExceptionInfo *exception)
2904 % A description of each parameter follows:
2906 % o image: the image.
2908 % o virtual_pixel_method: the virtual pixel method.
2910 % o x,y,columns,rows: These values define the perimeter of a region of
2913 % o nexus_info: the cache nexus to acquire.
2915 % o exception: return any errors or warnings in this structure.
2922 0, 48, 12, 60, 3, 51, 15, 63,
2923 32, 16, 44, 28, 35, 19, 47, 31,
2924 8, 56, 4, 52, 11, 59, 7, 55,
2925 40, 24, 36, 20, 43, 27, 39, 23,
2926 2, 50, 14, 62, 1, 49, 13, 61,
2927 34, 18, 46, 30, 33, 17, 45, 29,
2928 10, 58, 6, 54, 9, 57, 5, 53,
2929 42, 26, 38, 22, 41, 25, 37, 21
2932 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2937 index=x+DitherMatrix[x & 0x07]-32L;
2940 if (index >= (ssize_t) columns)
2941 return((ssize_t) columns-1L);
2945 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2950 index=y+DitherMatrix[y & 0x07]-32L;
2953 if (index >= (ssize_t) rows)
2954 return((ssize_t) rows-1L);
2958 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2962 if (x >= (ssize_t) columns)
2963 return((ssize_t) (columns-1));
2967 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2971 if (y >= (ssize_t) rows)
2972 return((ssize_t) (rows-1));
2976 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2978 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2981 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2983 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2986 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2987 const size_t extent)
2993 Compute the remainder of dividing offset by extent. It returns not only
2994 the quotient (tile the offset falls in) but also the positive remainer
2995 within that tile such that 0 <= remainder < extent. This method is
2996 essentially a ldiv() using a floored modulo division rather than the
2997 normal default truncated modulo division.
2999 modulo.quotient=offset/(ssize_t) extent;
3002 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3006 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3007 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3008 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3009 ExceptionInfo *exception)
3026 virtual_pixel[CompositePixelChannel];
3031 register const Quantum
3044 register unsigned char
3051 *virtual_metacontent;
3056 assert(image != (const Image *) NULL);
3057 assert(image->signature == MagickSignature);
3058 assert(image->cache != (Cache) NULL);
3059 cache_info=(CacheInfo *) image->cache;
3060 assert(cache_info->signature == MagickSignature);
3061 if (cache_info->type == UndefinedCache)
3062 return((const Quantum *) NULL);
3065 region.width=columns;
3067 pixels=SetPixelCacheNexusPixels(image,ReadMode,®ion,nexus_info,exception);
3068 if (pixels == (Quantum *) NULL)
3069 return((const Quantum *) NULL);
3071 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3072 nexus_info->region.x;
3073 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3074 nexus_info->region.width-1L;
3075 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3076 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3077 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3078 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3084 Pixel request is inside cache extents.
3086 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3088 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3089 if (status == MagickFalse)
3090 return((const Quantum *) NULL);
3091 if (cache_info->metacontent_extent != 0)
3093 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3094 if (status == MagickFalse)
3095 return((const Quantum *) NULL);
3100 Pixel request is outside cache extents.
3102 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3103 virtual_nexus=AcquirePixelCacheNexus(1);
3104 if (virtual_nexus == (NexusInfo **) NULL)
3106 if (virtual_nexus != (NexusInfo **) NULL)
3107 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3108 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3109 "UnableToGetCacheNexus","'%s'",image->filename);
3110 return((const Quantum *) NULL);
3112 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3113 sizeof(*virtual_pixel));
3114 virtual_metacontent=(void *) NULL;
3115 switch (virtual_pixel_method)
3117 case BackgroundVirtualPixelMethod:
3118 case BlackVirtualPixelMethod:
3119 case GrayVirtualPixelMethod:
3120 case TransparentVirtualPixelMethod:
3121 case MaskVirtualPixelMethod:
3122 case WhiteVirtualPixelMethod:
3123 case EdgeVirtualPixelMethod:
3124 case CheckerTileVirtualPixelMethod:
3125 case HorizontalTileVirtualPixelMethod:
3126 case VerticalTileVirtualPixelMethod:
3128 if (cache_info->metacontent_extent != 0)
3131 Acquire a metacontent buffer.
3133 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3134 cache_info->metacontent_extent);
3135 if (virtual_metacontent == (void *) NULL)
3137 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3138 (void) ThrowMagickException(exception,GetMagickModule(),
3139 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
3140 return((const Quantum *) NULL);
3142 (void) ResetMagickMemory(virtual_metacontent,0,
3143 cache_info->metacontent_extent);
3145 switch (virtual_pixel_method)
3147 case BlackVirtualPixelMethod:
3149 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3150 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3151 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3154 case GrayVirtualPixelMethod:
3156 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3157 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3159 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3162 case TransparentVirtualPixelMethod:
3164 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3165 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3166 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3169 case MaskVirtualPixelMethod:
3170 case WhiteVirtualPixelMethod:
3172 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3173 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3174 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3179 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3181 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3183 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3185 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3187 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3197 for (v=0; v < (ssize_t) rows; v++)
3199 for (u=0; u < (ssize_t) columns; u+=length)
3201 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3202 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3203 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3211 Transfer a single pixel.
3213 length=(MagickSizeType) 1;
3214 switch (virtual_pixel_method)
3218 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3219 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3220 1UL,1UL,*virtual_nexus,exception);
3221 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3224 case RandomVirtualPixelMethod:
3226 if (cache_info->random_info == (RandomInfo *) NULL)
3227 cache_info->random_info=AcquireRandomInfo();
3228 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3229 RandomX(cache_info->random_info,cache_info->columns),
3230 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3231 *virtual_nexus,exception);
3232 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3235 case DitherVirtualPixelMethod:
3237 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3238 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3239 1UL,1UL,*virtual_nexus,exception);
3240 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3243 case TileVirtualPixelMethod:
3245 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3246 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3247 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3248 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3250 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3253 case MirrorVirtualPixelMethod:
3255 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3256 if ((x_modulo.quotient & 0x01) == 1L)
3257 x_modulo.remainder=(ssize_t) cache_info->columns-
3258 x_modulo.remainder-1L;
3259 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3260 if ((y_modulo.quotient & 0x01) == 1L)
3261 y_modulo.remainder=(ssize_t) cache_info->rows-
3262 y_modulo.remainder-1L;
3263 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3264 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3266 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3269 case HorizontalTileEdgeVirtualPixelMethod:
3271 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3272 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3273 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3274 *virtual_nexus,exception);
3275 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3278 case VerticalTileEdgeVirtualPixelMethod:
3280 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3281 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3282 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3283 *virtual_nexus,exception);
3284 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3287 case BackgroundVirtualPixelMethod:
3288 case BlackVirtualPixelMethod:
3289 case GrayVirtualPixelMethod:
3290 case TransparentVirtualPixelMethod:
3291 case MaskVirtualPixelMethod:
3292 case WhiteVirtualPixelMethod:
3295 r=virtual_metacontent;
3298 case EdgeVirtualPixelMethod:
3299 case CheckerTileVirtualPixelMethod:
3301 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3302 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3303 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3306 r=virtual_metacontent;
3309 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3310 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3312 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3315 case HorizontalTileVirtualPixelMethod:
3317 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3320 r=virtual_metacontent;
3323 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3324 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3325 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3326 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3328 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3331 case VerticalTileVirtualPixelMethod:
3333 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3336 r=virtual_metacontent;
3339 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3340 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3341 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3342 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3344 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3348 if (p == (const Quantum *) NULL)
3350 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3352 q+=cache_info->number_channels;
3353 if ((s != (void *) NULL) && (r != (const void *) NULL))
3355 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3356 s+=cache_info->metacontent_extent;
3361 Transfer a run of pixels.
3363 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3364 length,1UL,*virtual_nexus,exception);
3365 if (p == (const Quantum *) NULL)
3367 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3368 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3369 q+=length*cache_info->number_channels;
3370 if ((r != (void *) NULL) && (s != (const void *) NULL))
3372 (void) memcpy(s,r,(size_t) length);
3373 s+=length*cache_info->metacontent_extent;
3380 if (virtual_metacontent != (void *) NULL)
3381 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3382 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3391 + G e t V i r t u a l P i x e l C a c h e %
3395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3397 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3398 % cache as defined by the geometry parameters. A pointer to the pixels
3399 % is returned if the pixels are transferred, otherwise a NULL is returned.
3401 % The format of the GetVirtualPixelCache() method is:
3403 % const Quantum *GetVirtualPixelCache(const Image *image,
3404 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3405 % const ssize_t y,const size_t columns,const size_t rows,
3406 % ExceptionInfo *exception)
3408 % A description of each parameter follows:
3410 % o image: the image.
3412 % o virtual_pixel_method: the virtual pixel method.
3414 % o x,y,columns,rows: These values define the perimeter of a region of
3417 % o exception: return any errors or warnings in this structure.
3420 static const Quantum *GetVirtualPixelCache(const Image *image,
3421 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3422 const size_t columns,const size_t rows,ExceptionInfo *exception)
3428 id = GetOpenMPThreadId();
3433 assert(image != (const Image *) NULL);
3434 assert(image->signature == MagickSignature);
3435 assert(image->cache != (Cache) NULL);
3436 cache_info=(CacheInfo *) image->cache;
3437 assert(cache_info->signature == MagickSignature);
3438 assert(id < (int) cache_info->number_threads);
3439 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3440 cache_info->nexus_info[id],exception);
3445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3449 % G e t V i r t u a l P i x e l Q u e u e %
3453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3455 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3456 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3458 % The format of the GetVirtualPixelQueue() method is:
3460 % const Quantum *GetVirtualPixelQueue(const Image image)
3462 % A description of each parameter follows:
3464 % o image: the image.
3467 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3473 id = GetOpenMPThreadId();
3475 assert(image != (const Image *) NULL);
3476 assert(image->signature == MagickSignature);
3477 assert(image->cache != (Cache) NULL);
3478 cache_info=(CacheInfo *) image->cache;
3479 assert(cache_info->signature == MagickSignature);
3480 if (cache_info->methods.get_virtual_pixels_handler !=
3481 (GetVirtualPixelsHandler) NULL)
3482 return(cache_info->methods.get_virtual_pixels_handler(image));
3483 assert(id < (int) cache_info->number_threads);
3484 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3492 % G e t V i r t u a l P i x e l s %
3496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3498 % GetVirtualPixels() returns an immutable pixel region. If the
3499 % region is successfully accessed, a pointer to it is returned, otherwise
3500 % NULL is returned. The returned pointer may point to a temporary working
3501 % copy of the pixels or it may point to the original pixels in memory.
3502 % Performance is maximized if the selected region is part of one row, or one
3503 % or more full rows, since there is opportunity to access the pixels in-place
3504 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3505 % returned pointer must *never* be deallocated by the user.
3507 % Pixels accessed via the returned pointer represent a simple array of type
3508 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3509 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3510 % access the meta-content (of type void) corresponding to the the
3513 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3515 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3516 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3517 % GetCacheViewAuthenticPixels() instead.
3519 % The format of the GetVirtualPixels() method is:
3521 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3522 % const ssize_t y,const size_t columns,const size_t rows,
3523 % ExceptionInfo *exception)
3525 % A description of each parameter follows:
3527 % o image: the image.
3529 % o x,y,columns,rows: These values define the perimeter of a region of
3532 % o exception: return any errors or warnings in this structure.
3535 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3536 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3537 ExceptionInfo *exception)
3543 id = GetOpenMPThreadId();
3548 assert(image != (const Image *) NULL);
3549 assert(image->signature == MagickSignature);
3550 assert(image->cache != (Cache) NULL);
3551 cache_info=(CacheInfo *) image->cache;
3552 assert(cache_info->signature == MagickSignature);
3553 if (cache_info->methods.get_virtual_pixel_handler !=
3554 (GetVirtualPixelHandler) NULL)
3555 return(cache_info->methods.get_virtual_pixel_handler(image,
3556 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3557 assert(id < (int) cache_info->number_threads);
3558 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3559 columns,rows,cache_info->nexus_info[id],exception);
3564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3568 + 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 %
3572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3574 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3575 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3577 % The format of the GetVirtualPixelsCache() method is:
3579 % Quantum *GetVirtualPixelsCache(const Image *image)
3581 % A description of each parameter follows:
3583 % o image: the image.
3586 static const Quantum *GetVirtualPixelsCache(const Image *image)
3592 id = GetOpenMPThreadId();
3594 assert(image != (const Image *) NULL);
3595 assert(image->signature == MagickSignature);
3596 assert(image->cache != (Cache) NULL);
3597 cache_info=(CacheInfo *) image->cache;
3598 assert(cache_info->signature == MagickSignature);
3599 assert(id < (int) cache_info->number_threads);
3600 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3608 + G e t V i r t u a l P i x e l s N e x u s %
3612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3617 % The format of the GetVirtualPixelsNexus() method is:
3619 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3620 % NexusInfo *nexus_info)
3622 % A description of each parameter follows:
3624 % o cache: the pixel cache.
3626 % o nexus_info: the cache nexus to return the colormap pixels.
3629 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3630 NexusInfo *nexus_info)
3635 assert(cache != (Cache) NULL);
3636 cache_info=(CacheInfo *) cache;
3637 assert(cache_info->signature == MagickSignature);
3638 if (cache_info->storage_class == UndefinedClass)
3639 return((Quantum *) NULL);
3640 return((const Quantum *) nexus_info->pixels);
3644 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3648 + O p e n P i x e l C a c h e %
3652 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3655 % dimensions, allocating space for the image pixels and optionally the
3656 % metacontent, and memory mapping the cache if it is disk based. The cache
3657 % nexus array is initialized as well.
3659 % The format of the OpenPixelCache() method is:
3661 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3662 % ExceptionInfo *exception)
3664 % A description of each parameter follows:
3666 % o image: the image.
3668 % o mode: ReadMode, WriteMode, or IOMode.
3670 % o exception: return any errors or warnings in this structure.
3674 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3676 cache_info->mapped=MagickFalse;
3677 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3678 cache_info->length);
3679 if (cache_info->pixels == (Quantum *) NULL)
3681 cache_info->mapped=MagickTrue;
3682 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3683 cache_info->length);
3687 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3697 cache_info=(CacheInfo *) image->cache;
3698 if (image->debug != MagickFalse)
3701 format[MaxTextExtent],
3702 message[MaxTextExtent];
3704 (void) FormatMagickSize(length,MagickFalse,format);
3705 (void) FormatLocaleString(message,MaxTextExtent,
3706 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3707 cache_info->cache_filename,cache_info->file,format);
3708 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3710 if (length != (MagickSizeType) ((MagickOffsetType) length))
3711 return(MagickFalse);
3712 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3714 return(MagickFalse);
3715 if ((MagickSizeType) extent >= length)
3717 offset=(MagickOffsetType) length-1;
3718 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3719 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3722 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3723 ExceptionInfo *exception)
3730 format[MaxTextExtent],
3731 message[MaxTextExtent];
3744 assert(image != (const Image *) NULL);
3745 assert(image->signature == MagickSignature);
3746 assert(image->cache != (Cache) NULL);
3747 if (image->debug != MagickFalse)
3748 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3749 if ((image->columns == 0) || (image->rows == 0))
3750 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3751 cache_info=(CacheInfo *) image->cache;
3752 assert(cache_info->signature == MagickSignature);
3753 source_info=(*cache_info);
3754 source_info.file=(-1);
3755 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3756 image->filename,(double) GetImageIndexInList(image));
3757 cache_info->storage_class=image->storage_class;
3758 cache_info->colorspace=image->colorspace;
3759 cache_info->matte=image->matte;
3760 cache_info->mask=image->mask;
3761 cache_info->rows=image->rows;
3762 cache_info->columns=image->columns;
3763 InitializePixelChannelMap(image);
3764 cache_info->number_channels=GetPixelChannels(image);
3765 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3766 sizeof(*image->channel_map));
3767 cache_info->metacontent_extent=image->metacontent_extent;
3768 cache_info->mode=mode;
3769 if (image->ping != MagickFalse)
3771 cache_info->type=PingCache;
3772 cache_info->pixels=(Quantum *) NULL;
3773 cache_info->metacontent=(void *) NULL;
3774 cache_info->length=0;
3777 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3778 packet_size=cache_info->number_channels*sizeof(Quantum);
3779 if (image->metacontent_extent != 0)
3780 packet_size+=cache_info->metacontent_extent;
3781 length=number_pixels*packet_size;
3782 columns=(size_t) (length/cache_info->rows/packet_size);
3783 if (cache_info->columns != columns)
3784 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3786 cache_info->length=length;
3787 status=AcquireMagickResource(AreaResource,cache_info->length);
3788 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3789 cache_info->metacontent_extent);
3790 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3792 status=AcquireMagickResource(MemoryResource,cache_info->length);
3793 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3794 (cache_info->type == MemoryCache))
3796 AllocatePixelCachePixels(cache_info);
3797 if (cache_info->pixels == (Quantum *) NULL)
3798 cache_info->pixels=source_info.pixels;
3802 Create memory pixel cache.
3805 if (image->debug != MagickFalse)
3807 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3808 (void) FormatLocaleString(message,MaxTextExtent,
3809 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3810 cache_info->filename,cache_info->mapped != MagickFalse ?
3811 "anonymous" : "heap",(double) cache_info->columns,(double)
3812 cache_info->rows,(double) cache_info->number_channels,
3814 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3817 cache_info->type=MemoryCache;
3818 cache_info->metacontent=(void *) NULL;
3819 if (cache_info->metacontent_extent != 0)
3820 cache_info->metacontent=(void *) (cache_info->pixels+
3821 number_pixels*cache_info->number_channels);
3822 if ((source_info.storage_class != UndefinedClass) &&
3825 status=ClonePixelCachePixels(cache_info,&source_info,
3827 RelinquishPixelCachePixels(&source_info);
3832 RelinquishMagickResource(MemoryResource,cache_info->length);
3835 Create pixel cache on disk.
3837 status=AcquireMagickResource(DiskResource,cache_info->length);
3838 if (status == MagickFalse)
3840 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3841 "CacheResourcesExhausted","'%s'",image->filename);
3842 return(MagickFalse);
3844 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3846 (void) ClosePixelCacheOnDisk(cache_info);
3847 *cache_info->cache_filename='\0';
3849 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3851 RelinquishMagickResource(DiskResource,cache_info->length);
3852 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3854 return(MagickFalse);
3856 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3857 cache_info->length);
3858 if (status == MagickFalse)
3860 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3862 return(MagickFalse);
3864 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3865 cache_info->metacontent_extent);
3866 if (length != (MagickSizeType) ((size_t) length))
3867 cache_info->type=DiskCache;
3870 status=AcquireMagickResource(MapResource,cache_info->length);
3871 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3872 (cache_info->type != MemoryCache))
3873 cache_info->type=DiskCache;
3876 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3877 cache_info->offset,(size_t) cache_info->length);
3878 if (cache_info->pixels == (Quantum *) NULL)
3880 cache_info->type=DiskCache;
3881 cache_info->pixels=source_info.pixels;
3886 Create file-backed memory-mapped pixel cache.
3889 (void) ClosePixelCacheOnDisk(cache_info);
3890 cache_info->type=MapCache;
3891 cache_info->mapped=MagickTrue;
3892 cache_info->metacontent=(void *) NULL;
3893 if (cache_info->metacontent_extent != 0)
3894 cache_info->metacontent=(void *) (cache_info->pixels+
3895 number_pixels*cache_info->number_channels);
3896 if ((source_info.storage_class != UndefinedClass) &&
3899 status=ClonePixelCachePixels(cache_info,&source_info,
3901 RelinquishPixelCachePixels(&source_info);
3903 if (image->debug != MagickFalse)
3905 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3906 (void) FormatLocaleString(message,MaxTextExtent,
3907 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
3908 cache_info->filename,cache_info->cache_filename,
3909 cache_info->file,(double) cache_info->columns,(double)
3910 cache_info->rows,(double) cache_info->number_channels,
3912 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3918 RelinquishMagickResource(MapResource,cache_info->length);
3921 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3923 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3924 RelinquishPixelCachePixels(&source_info);
3926 if (image->debug != MagickFalse)
3928 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3929 (void) FormatLocaleString(message,MaxTextExtent,
3930 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
3931 cache_info->cache_filename,cache_info->file,(double)
3932 cache_info->columns,(double) cache_info->rows,(double)
3933 cache_info->number_channels,format);
3934 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3944 + P e r s i s t P i x e l C a c h e %
3948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3950 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3951 % persistent pixel cache is one that resides on disk and is not destroyed
3952 % when the program exits.
3954 % The format of the PersistPixelCache() method is:
3956 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3957 % const MagickBooleanType attach,MagickOffsetType *offset,
3958 % ExceptionInfo *exception)
3960 % A description of each parameter follows:
3962 % o image: the image.
3964 % o filename: the persistent pixel cache filename.
3966 % o attach: A value other than zero initializes the persistent pixel cache.
3968 % o initialize: A value other than zero initializes the persistent pixel
3971 % o offset: the offset in the persistent cache to store pixels.
3973 % o exception: return any errors or warnings in this structure.
3976 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3977 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3978 ExceptionInfo *exception)
3993 assert(image != (Image *) NULL);
3994 assert(image->signature == MagickSignature);
3995 if (image->debug != MagickFalse)
3996 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3997 assert(image->cache != (void *) NULL);
3998 assert(filename != (const char *) NULL);
3999 assert(offset != (MagickOffsetType *) NULL);
4000 page_size=GetMagickPageSize();
4001 cache_info=(CacheInfo *) image->cache;
4002 assert(cache_info->signature == MagickSignature);
4003 if (attach != MagickFalse)
4006 Attach existing persistent pixel cache.
4008 if (image->debug != MagickFalse)
4009 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4010 "attach persistent cache");
4011 (void) CopyMagickString(cache_info->cache_filename,filename,
4013 cache_info->type=DiskCache;
4014 cache_info->offset=(*offset);
4015 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4016 return(MagickFalse);
4017 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4020 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4021 (cache_info->reference_count == 1))
4023 LockSemaphoreInfo(cache_info->semaphore);
4024 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4025 (cache_info->reference_count == 1))
4031 Usurp existing persistent pixel cache.
4033 status=rename_utf8(cache_info->cache_filename,filename);
4036 (void) CopyMagickString(cache_info->cache_filename,filename,
4038 *offset+=cache_info->length+page_size-(cache_info->length %
4040 UnlockSemaphoreInfo(cache_info->semaphore);
4041 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4042 if (image->debug != MagickFalse)
4043 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4044 "Usurp resident persistent cache");
4048 UnlockSemaphoreInfo(cache_info->semaphore);
4051 Clone persistent pixel cache.
4053 clone_image=(*image);
4054 clone_info=(CacheInfo *) clone_image.cache;
4055 image->cache=ClonePixelCache(cache_info);
4056 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4057 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4058 cache_info->type=DiskCache;
4059 cache_info->offset=(*offset);
4060 cache_info=(CacheInfo *) image->cache;
4061 status=OpenPixelCache(image,IOMode,exception);
4062 if (status != MagickFalse)
4063 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4064 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4065 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4074 + 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 %
4078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4080 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4081 % defined by the region rectangle and returns a pointer to the region. This
4082 % region is subsequently transferred from the pixel cache with
4083 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4084 % pixels are transferred, otherwise a NULL is returned.
4086 % The format of the QueueAuthenticPixelCacheNexus() method is:
4088 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4089 % const ssize_t y,const size_t columns,const size_t rows,
4090 % const MagickBooleanType clone,NexusInfo *nexus_info,
4091 % ExceptionInfo *exception)
4093 % A description of each parameter follows:
4095 % o image: the image.
4097 % o x,y,columns,rows: These values define the perimeter of a region of
4100 % o nexus_info: the cache nexus to set.
4102 % o clone: clone the pixel cache.
4104 % o exception: return any errors or warnings in this structure.
4107 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4108 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4109 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4124 Validate pixel cache geometry.
4126 assert(image != (const Image *) NULL);
4127 assert(image->signature == MagickSignature);
4128 assert(image->cache != (Cache) NULL);
4129 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4130 if (cache_info == (Cache) NULL)
4131 return((Quantum *) NULL);
4132 assert(cache_info->signature == MagickSignature);
4133 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4135 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4136 "NoPixelsDefinedInCache","'%s'",image->filename);
4137 return((Quantum *) NULL);
4139 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4140 (y >= (ssize_t) cache_info->rows))
4142 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4143 "PixelsAreNotAuthentic","'%s'",image->filename);
4144 return((Quantum *) NULL);
4146 offset=(MagickOffsetType) y*cache_info->columns+x;
4148 return((Quantum *) NULL);
4149 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4150 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4151 if ((MagickSizeType) offset >= number_pixels)
4152 return((Quantum *) NULL);
4158 region.width=columns;
4160 return(SetPixelCacheNexusPixels(image,WriteMode,®ion,nexus_info,exception));
4164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4168 + 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 %
4172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4174 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4175 % defined by the region rectangle and returns a pointer to the region. This
4176 % region is subsequently transferred from the pixel cache with
4177 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4178 % pixels are transferred, otherwise a NULL is returned.
4180 % The format of the QueueAuthenticPixelsCache() method is:
4182 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4183 % const ssize_t y,const size_t columns,const size_t rows,
4184 % ExceptionInfo *exception)
4186 % A description of each parameter follows:
4188 % o image: the image.
4190 % o x,y,columns,rows: These values define the perimeter of a region of
4193 % o exception: return any errors or warnings in this structure.
4196 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4197 const ssize_t y,const size_t columns,const size_t rows,
4198 ExceptionInfo *exception)
4204 id = GetOpenMPThreadId();
4209 assert(image != (const Image *) NULL);
4210 assert(image->signature == MagickSignature);
4211 assert(image->cache != (Cache) NULL);
4212 cache_info=(CacheInfo *) image->cache;
4213 assert(cache_info->signature == MagickSignature);
4214 assert(id < (int) cache_info->number_threads);
4215 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4216 cache_info->nexus_info[id],exception);
4221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4225 % Q u e u e A u t h e n t i c P i x e l s %
4229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4231 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4232 % successfully initialized a pointer to a Quantum array representing the
4233 % region is returned, otherwise NULL is returned. The returned pointer may
4234 % point to a temporary working buffer for the pixels or it may point to the
4235 % final location of the pixels in memory.
4237 % Write-only access means that any existing pixel values corresponding to
4238 % the region are ignored. This is useful if the initial image is being
4239 % created from scratch, or if the existing pixel values are to be
4240 % completely replaced without need to refer to their pre-existing values.
4241 % The application is free to read and write the pixel buffer returned by
4242 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4243 % initialize the pixel array values. Initializing pixel array values is the
4244 % application's responsibility.
4246 % Performance is maximized if the selected region is part of one row, or
4247 % one or more full rows, since then there is opportunity to access the
4248 % pixels in-place (without a copy) if the image is in memory, or in a
4249 % memory-mapped file. The returned pointer must *never* be deallocated
4252 % Pixels accessed via the returned pointer represent a simple array of type
4253 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4254 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4255 % obtain the meta-content (of type void) corresponding to the region.
4256 % Once the Quantum (and/or Quantum) array has been updated, the
4257 % changes must be saved back to the underlying image using
4258 % SyncAuthenticPixels() or they may be lost.
4260 % The format of the QueueAuthenticPixels() method is:
4262 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4263 % const ssize_t y,const size_t columns,const size_t rows,
4264 % ExceptionInfo *exception)
4266 % A description of each parameter follows:
4268 % o image: the image.
4270 % o x,y,columns,rows: These values define the perimeter of a region of
4273 % o exception: return any errors or warnings in this structure.
4276 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4277 const ssize_t y,const size_t columns,const size_t rows,
4278 ExceptionInfo *exception)
4284 id = GetOpenMPThreadId();
4289 assert(image != (Image *) NULL);
4290 assert(image->signature == MagickSignature);
4291 assert(image->cache != (Cache) NULL);
4292 cache_info=(CacheInfo *) image->cache;
4293 assert(cache_info->signature == MagickSignature);
4294 if (cache_info->methods.queue_authentic_pixels_handler !=
4295 (QueueAuthenticPixelsHandler) NULL)
4297 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4301 assert(id < (int) cache_info->number_threads);
4302 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4303 cache_info->nexus_info[id],exception);
4308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4312 + 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 %
4316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4318 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4321 % The format of the ReadPixelCacheMetacontent() method is:
4323 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4324 % NexusInfo *nexus_info,ExceptionInfo *exception)
4326 % A description of each parameter follows:
4328 % o cache_info: the pixel cache.
4330 % o nexus_info: the cache nexus to read the metacontent.
4332 % o exception: return any errors or warnings in this structure.
4335 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4336 NexusInfo *nexus_info,ExceptionInfo *exception)
4349 register unsigned char
4355 if (cache_info->metacontent_extent == 0)
4356 return(MagickFalse);
4357 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4359 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4360 nexus_info->region.x;
4361 length=(MagickSizeType) nexus_info->region.width*
4362 cache_info->metacontent_extent;
4363 rows=nexus_info->region.height;
4365 q=(unsigned char *) nexus_info->metacontent;
4366 switch (cache_info->type)
4371 register unsigned char
4375 Read meta-content from memory.
4377 if ((cache_info->columns == nexus_info->region.width) &&
4378 (extent == (MagickSizeType) ((size_t) extent)))
4383 p=(unsigned char *) cache_info->metacontent+offset*
4384 cache_info->metacontent_extent;
4385 for (y=0; y < (ssize_t) rows; y++)
4387 (void) memcpy(q,p,(size_t) length);
4388 p+=cache_info->metacontent_extent*cache_info->columns;
4389 q+=cache_info->metacontent_extent*nexus_info->region.width;
4396 Read meta content from disk.
4398 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4400 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4401 cache_info->cache_filename);
4402 return(MagickFalse);
4404 if ((cache_info->columns == nexus_info->region.width) &&
4405 (extent <= MagickMaxBufferExtent))
4410 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4411 for (y=0; y < (ssize_t) rows; y++)
4413 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4414 cache_info->number_channels*sizeof(Quantum)+offset*
4415 cache_info->metacontent_extent,length,(unsigned char *) q);
4416 if ((MagickSizeType) count != length)
4418 offset+=cache_info->columns;
4419 q+=cache_info->metacontent_extent*nexus_info->region.width;
4421 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4422 (void) ClosePixelCacheOnDisk(cache_info);
4423 if (y < (ssize_t) rows)
4425 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4426 cache_info->cache_filename);
4427 return(MagickFalse);
4434 if ((cache_info->debug != MagickFalse) &&
4435 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4436 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4437 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4438 nexus_info->region.width,(double) nexus_info->region.height,(double)
4439 nexus_info->region.x,(double) nexus_info->region.y);
4444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4448 + R e a d P i x e l C a c h e P i x e l s %
4452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4454 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4457 % The format of the ReadPixelCachePixels() method is:
4459 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4460 % NexusInfo *nexus_info,ExceptionInfo *exception)
4462 % A description of each parameter follows:
4464 % o cache_info: the pixel cache.
4466 % o nexus_info: the cache nexus to read the pixels.
4468 % o exception: return any errors or warnings in this structure.
4471 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4472 NexusInfo *nexus_info,ExceptionInfo *exception)
4491 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4493 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4494 nexus_info->region.x;
4495 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4497 rows=nexus_info->region.height;
4499 q=nexus_info->pixels;
4500 switch (cache_info->type)
4509 Read pixels from memory.
4511 if ((cache_info->columns == nexus_info->region.width) &&
4512 (extent == (MagickSizeType) ((size_t) extent)))
4517 p=cache_info->pixels+offset*cache_info->number_channels;
4518 for (y=0; y < (ssize_t) rows; y++)
4520 (void) memcpy(q,p,(size_t) length);
4521 p+=cache_info->number_channels*cache_info->columns;
4522 q+=cache_info->number_channels*nexus_info->region.width;
4529 Read pixels from disk.
4531 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4533 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4534 cache_info->cache_filename);
4535 return(MagickFalse);
4537 if ((cache_info->columns == nexus_info->region.width) &&
4538 (extent <= MagickMaxBufferExtent))
4543 for (y=0; y < (ssize_t) rows; y++)
4545 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4546 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4547 if ((MagickSizeType) count != length)
4549 offset+=cache_info->columns;
4550 q+=cache_info->number_channels*nexus_info->region.width;
4552 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4553 (void) ClosePixelCacheOnDisk(cache_info);
4554 if (y < (ssize_t) rows)
4556 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4557 cache_info->cache_filename);
4558 return(MagickFalse);
4565 if ((cache_info->debug != MagickFalse) &&
4566 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4567 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4568 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4569 nexus_info->region.width,(double) nexus_info->region.height,(double)
4570 nexus_info->region.x,(double) nexus_info->region.y);
4575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4579 + R e f e r e n c e P i x e l C a c h e %
4583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4585 % ReferencePixelCache() increments the reference count associated with the
4586 % pixel cache returning a pointer to the cache.
4588 % The format of the ReferencePixelCache method is:
4590 % Cache ReferencePixelCache(Cache cache_info)
4592 % A description of each parameter follows:
4594 % o cache_info: the pixel cache.
4597 MagickPrivate Cache ReferencePixelCache(Cache cache)
4602 assert(cache != (Cache *) NULL);
4603 cache_info=(CacheInfo *) cache;
4604 assert(cache_info->signature == MagickSignature);
4605 LockSemaphoreInfo(cache_info->semaphore);
4606 cache_info->reference_count++;
4607 UnlockSemaphoreInfo(cache_info->semaphore);
4612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4616 + S e t P i x e l C a c h e M e t h o d s %
4620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4622 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4624 % The format of the SetPixelCacheMethods() method is:
4626 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4628 % A description of each parameter follows:
4630 % o cache: the pixel cache.
4632 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4635 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4640 GetOneAuthenticPixelFromHandler
4641 get_one_authentic_pixel_from_handler;
4643 GetOneVirtualPixelFromHandler
4644 get_one_virtual_pixel_from_handler;
4647 Set cache pixel methods.
4649 assert(cache != (Cache) NULL);
4650 assert(cache_methods != (CacheMethods *) NULL);
4651 cache_info=(CacheInfo *) cache;
4652 assert(cache_info->signature == MagickSignature);
4653 if (cache_info->debug != MagickFalse)
4654 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4655 cache_info->filename);
4656 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4657 cache_info->methods.get_virtual_pixel_handler=
4658 cache_methods->get_virtual_pixel_handler;
4659 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4660 cache_info->methods.destroy_pixel_handler=
4661 cache_methods->destroy_pixel_handler;
4662 if (cache_methods->get_virtual_metacontent_from_handler !=
4663 (GetVirtualMetacontentFromHandler) NULL)
4664 cache_info->methods.get_virtual_metacontent_from_handler=
4665 cache_methods->get_virtual_metacontent_from_handler;
4666 if (cache_methods->get_authentic_pixels_handler !=
4667 (GetAuthenticPixelsHandler) NULL)
4668 cache_info->methods.get_authentic_pixels_handler=
4669 cache_methods->get_authentic_pixels_handler;
4670 if (cache_methods->queue_authentic_pixels_handler !=
4671 (QueueAuthenticPixelsHandler) NULL)
4672 cache_info->methods.queue_authentic_pixels_handler=
4673 cache_methods->queue_authentic_pixels_handler;
4674 if (cache_methods->sync_authentic_pixels_handler !=
4675 (SyncAuthenticPixelsHandler) NULL)
4676 cache_info->methods.sync_authentic_pixels_handler=
4677 cache_methods->sync_authentic_pixels_handler;
4678 if (cache_methods->get_authentic_pixels_from_handler !=
4679 (GetAuthenticPixelsFromHandler) NULL)
4680 cache_info->methods.get_authentic_pixels_from_handler=
4681 cache_methods->get_authentic_pixels_from_handler;
4682 if (cache_methods->get_authentic_metacontent_from_handler !=
4683 (GetAuthenticMetacontentFromHandler) NULL)
4684 cache_info->methods.get_authentic_metacontent_from_handler=
4685 cache_methods->get_authentic_metacontent_from_handler;
4686 get_one_virtual_pixel_from_handler=
4687 cache_info->methods.get_one_virtual_pixel_from_handler;
4688 if (get_one_virtual_pixel_from_handler !=
4689 (GetOneVirtualPixelFromHandler) NULL)
4690 cache_info->methods.get_one_virtual_pixel_from_handler=
4691 cache_methods->get_one_virtual_pixel_from_handler;
4692 get_one_authentic_pixel_from_handler=
4693 cache_methods->get_one_authentic_pixel_from_handler;
4694 if (get_one_authentic_pixel_from_handler !=
4695 (GetOneAuthenticPixelFromHandler) NULL)
4696 cache_info->methods.get_one_authentic_pixel_from_handler=
4697 cache_methods->get_one_authentic_pixel_from_handler;
4701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4705 + S e t P i x e l C a c h e N e x u s P i x e l s %
4709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4711 % SetPixelCacheNexusPixels() defines the region of the cache for the
4712 % specified cache nexus.
4714 % The format of the SetPixelCacheNexusPixels() method is:
4716 % Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4717 % const RectangleInfo *region,NexusInfo *nexus_info,
4718 % ExceptionInfo *exception)
4720 % A description of each parameter follows:
4722 % o image: the image.
4724 % o mode: ReadMode, WriteMode, or IOMode.
4726 % o region: A pointer to the RectangleInfo structure that defines the
4727 % region of this particular cache nexus.
4729 % o nexus_info: the cache nexus to set.
4731 % o exception: return any errors or warnings in this structure.
4735 static inline MagickBooleanType AcquireCacheNexusPixels(
4736 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4737 ExceptionInfo *exception)
4739 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4740 return(MagickFalse);
4741 nexus_info->mapped=MagickFalse;
4742 nexus_info->cache=(Quantum *) AcquireMagickMemory((size_t)
4743 nexus_info->length);
4744 if (nexus_info->cache == (Quantum *) NULL)
4746 nexus_info->mapped=MagickTrue;
4747 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4748 nexus_info->length);
4750 if (nexus_info->cache == (Quantum *) NULL)
4752 (void) ThrowMagickException(exception,GetMagickModule(),
4753 ResourceLimitError,"MemoryAllocationFailed","'%s'",
4754 cache_info->filename);
4755 return(MagickFalse);
4760 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4763 if (mode == ReadMode)
4765 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4768 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4771 static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4772 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4784 cache_info=(CacheInfo *) image->cache;
4785 assert(cache_info->signature == MagickSignature);
4786 if (cache_info->type == UndefinedCache)
4787 return((Quantum *) NULL);
4788 nexus_info->region=(*region);
4789 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
4795 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4796 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4797 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4798 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4799 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4800 ((nexus_info->region.width == cache_info->columns) ||
4801 ((nexus_info->region.width % cache_info->columns) == 0)))))
4807 Pixels are accessed directly from memory.
4809 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4810 nexus_info->region.x;
4811 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4813 nexus_info->metacontent=(void *) NULL;
4814 if (cache_info->metacontent_extent != 0)
4815 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4816 offset*cache_info->metacontent_extent;
4817 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4818 return(nexus_info->pixels);
4822 Pixels are stored in a cache region until they are synced to the cache.
4824 number_pixels=(MagickSizeType) nexus_info->region.width*
4825 nexus_info->region.height;
4826 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4827 if (cache_info->metacontent_extent != 0)
4828 length+=number_pixels*cache_info->metacontent_extent;
4829 if (nexus_info->cache == (Quantum *) NULL)
4831 nexus_info->length=length;
4832 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4833 if (status == MagickFalse)
4835 nexus_info->length=0;
4836 return((Quantum *) NULL);
4840 if (nexus_info->length != length)
4842 RelinquishCacheNexusPixels(nexus_info);
4843 nexus_info->length=length;
4844 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4845 if (status == MagickFalse)
4847 nexus_info->length=0;
4848 return((Quantum *) NULL);
4851 nexus_info->pixels=nexus_info->cache;
4852 nexus_info->metacontent=(void *) NULL;
4853 if (cache_info->metacontent_extent != 0)
4854 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4855 cache_info->number_channels);
4856 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4857 return(nexus_info->pixels);
4861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4865 % 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 %
4869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4871 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4872 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4873 % access that is outside the boundaries of the image cache.
4875 % The format of the SetPixelCacheVirtualMethod() method is:
4877 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4878 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4880 % A description of each parameter follows:
4882 % o image: the image.
4884 % o virtual_pixel_method: choose the type of virtual pixel.
4886 % o exception: return any errors or warnings in this structure.
4890 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4891 ExceptionInfo *exception)
4905 assert(image != (Image *) NULL);
4906 assert(image->signature == MagickSignature);
4907 if (image->debug != MagickFalse)
4908 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4909 assert(image->cache != (Cache) NULL);
4910 cache_info=(CacheInfo *) image->cache;
4911 assert(cache_info->signature == MagickSignature);
4912 image->matte=MagickTrue;
4914 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4915 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4916 #pragma omp parallel for schedule(static) shared(status) \
4917 dynamic_number_threads(image,image->columns,image->rows,1)
4919 for (y=0; y < (ssize_t) image->rows; y++)
4927 if (status == MagickFalse)
4929 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4930 if (q == (Quantum *) NULL)
4935 for (x=0; x < (ssize_t) image->columns; x++)
4937 SetPixelAlpha(image,alpha,q);
4938 q+=GetPixelChannels(image);
4940 status=SyncCacheViewAuthenticPixels(image_view,exception);
4942 image_view=DestroyCacheView(image_view);
4946 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4947 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4955 assert(image != (Image *) NULL);
4956 assert(image->signature == MagickSignature);
4957 if (image->debug != MagickFalse)
4958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4959 assert(image->cache != (Cache) NULL);
4960 cache_info=(CacheInfo *) image->cache;
4961 assert(cache_info->signature == MagickSignature);
4962 method=cache_info->virtual_pixel_method;
4963 cache_info->virtual_pixel_method=virtual_pixel_method;
4964 if ((image->columns != 0) && (image->rows != 0))
4965 switch (virtual_pixel_method)
4967 case BackgroundVirtualPixelMethod:
4969 if ((image->background_color.matte != MagickFalse) &&
4970 (image->matte == MagickFalse))
4971 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4974 case TransparentVirtualPixelMethod:
4976 if (image->matte == MagickFalse)
4977 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4991 + S y n c A u t h e n t i c P i x e l C a c h e N e x u s %
4995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4997 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4998 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4999 % is synced, otherwise MagickFalse.
5001 % The format of the SyncAuthenticPixelCacheNexus() method is:
5003 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5004 % NexusInfo *nexus_info,ExceptionInfo *exception)
5006 % A description of each parameter follows:
5008 % o image: the image.
5010 % o nexus_info: the cache nexus to sync.
5012 % o exception: return any errors or warnings in this structure.
5015 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5016 NexusInfo *nexus_info,ExceptionInfo *exception)
5025 Transfer pixels to the cache.
5027 assert(image != (Image *) NULL);
5028 assert(image->signature == MagickSignature);
5029 if (image->cache == (Cache) NULL)
5030 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5031 cache_info=(CacheInfo *) image->cache;
5032 assert(cache_info->signature == MagickSignature);
5033 if (cache_info->type == UndefinedCache)
5034 return(MagickFalse);
5035 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5037 assert(cache_info->signature == MagickSignature);
5038 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5039 if ((cache_info->metacontent_extent != 0) &&
5040 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5041 return(MagickFalse);
5046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5050 + S y n c A u t h e n t i c P i x e l C a c h e %
5054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5056 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5057 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5058 % otherwise MagickFalse.
5060 % The format of the SyncAuthenticPixelsCache() method is:
5062 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5063 % ExceptionInfo *exception)
5065 % A description of each parameter follows:
5067 % o image: the image.
5069 % o exception: return any errors or warnings in this structure.
5072 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5073 ExceptionInfo *exception)
5079 id = GetOpenMPThreadId();
5084 assert(image != (Image *) NULL);
5085 assert(image->signature == MagickSignature);
5086 assert(image->cache != (Cache) NULL);
5087 cache_info=(CacheInfo *) image->cache;
5088 assert(cache_info->signature == MagickSignature);
5089 assert(id < (int) cache_info->number_threads);
5090 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5100 % S y n c A u t h e n t i c P i x e l s %
5104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5106 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5107 % The method returns MagickTrue if the pixel region is flushed, otherwise
5110 % The format of the SyncAuthenticPixels() method is:
5112 % MagickBooleanType SyncAuthenticPixels(Image *image,
5113 % ExceptionInfo *exception)
5115 % A description of each parameter follows:
5117 % o image: the image.
5119 % o exception: return any errors or warnings in this structure.
5122 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5123 ExceptionInfo *exception)
5129 id = GetOpenMPThreadId();
5134 assert(image != (Image *) NULL);
5135 assert(image->signature == MagickSignature);
5136 assert(image->cache != (Cache) NULL);
5137 cache_info=(CacheInfo *) image->cache;
5138 assert(cache_info->signature == MagickSignature);
5139 if (cache_info->methods.sync_authentic_pixels_handler !=
5140 (SyncAuthenticPixelsHandler) NULL)
5142 status=cache_info->methods.sync_authentic_pixels_handler(image,
5146 assert(id < (int) cache_info->number_threads);
5147 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5157 + S y n c I m a g e P i x e l C a c h e %
5161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5163 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5164 % The method returns MagickTrue if the pixel region is flushed, otherwise
5167 % The format of the SyncImagePixelCache() method is:
5169 % MagickBooleanType SyncImagePixelCache(Image *image,
5170 % ExceptionInfo *exception)
5172 % A description of each parameter follows:
5174 % o image: the image.
5176 % o exception: return any errors or warnings in this structure.
5179 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5180 ExceptionInfo *exception)
5185 assert(image != (Image *) NULL);
5186 assert(exception != (ExceptionInfo *) NULL);
5187 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5188 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5196 + 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 %
5200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5202 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5203 % of the pixel cache.
5205 % The format of the WritePixelCacheMetacontent() method is:
5207 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5208 % NexusInfo *nexus_info,ExceptionInfo *exception)
5210 % A description of each parameter follows:
5212 % o cache_info: the pixel cache.
5214 % o nexus_info: the cache nexus to write the meta-content.
5216 % o exception: return any errors or warnings in this structure.
5219 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5220 NexusInfo *nexus_info,ExceptionInfo *exception)
5230 register const unsigned char
5239 if (cache_info->metacontent_extent == 0)
5240 return(MagickFalse);
5241 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5243 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5244 nexus_info->region.x;
5245 length=(MagickSizeType) nexus_info->region.width*
5246 cache_info->metacontent_extent;
5247 rows=nexus_info->region.height;
5248 extent=(MagickSizeType) length*rows;
5249 p=(unsigned char *) nexus_info->metacontent;
5250 switch (cache_info->type)
5255 register unsigned char
5259 Write associated pixels to memory.
5261 if ((cache_info->columns == nexus_info->region.width) &&
5262 (extent == (MagickSizeType) ((size_t) extent)))
5267 q=(unsigned char *) cache_info->metacontent+offset*
5268 cache_info->metacontent_extent;
5269 for (y=0; y < (ssize_t) rows; y++)
5271 (void) memcpy(q,p,(size_t) length);
5272 p+=nexus_info->region.width*cache_info->metacontent_extent;
5273 q+=cache_info->columns*cache_info->metacontent_extent;
5280 Write associated pixels to disk.
5282 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5284 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5285 cache_info->cache_filename);
5286 return(MagickFalse);
5288 if ((cache_info->columns == nexus_info->region.width) &&
5289 (extent <= MagickMaxBufferExtent))
5294 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5295 for (y=0; y < (ssize_t) rows; y++)
5297 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5298 cache_info->number_channels*sizeof(Quantum)+offset*
5299 cache_info->metacontent_extent,length,(const unsigned char *) p);
5300 if ((MagickSizeType) count != length)
5302 p+=nexus_info->region.width*cache_info->metacontent_extent;
5303 offset+=cache_info->columns;
5305 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5306 (void) ClosePixelCacheOnDisk(cache_info);
5307 if (y < (ssize_t) rows)
5309 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5310 cache_info->cache_filename);
5311 return(MagickFalse);
5318 if ((cache_info->debug != MagickFalse) &&
5319 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5320 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5321 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5322 nexus_info->region.width,(double) nexus_info->region.height,(double)
5323 nexus_info->region.x,(double) nexus_info->region.y);
5328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5332 + W r i t e C a c h e P i x e l s %
5336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5338 % WritePixelCachePixels() writes image pixels to the specified region of the
5341 % The format of the WritePixelCachePixels() method is:
5343 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5344 % NexusInfo *nexus_info,ExceptionInfo *exception)
5346 % A description of each parameter follows:
5348 % o cache_info: the pixel cache.
5350 % o nexus_info: the cache nexus to write the pixels.
5352 % o exception: return any errors or warnings in this structure.
5355 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5356 NexusInfo *nexus_info,ExceptionInfo *exception)
5366 register const Quantum
5375 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5377 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5378 nexus_info->region.x;
5379 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5381 rows=nexus_info->region.height;
5383 p=nexus_info->pixels;
5384 switch (cache_info->type)
5393 Write pixels to memory.
5395 if ((cache_info->columns == nexus_info->region.width) &&
5396 (extent == (MagickSizeType) ((size_t) extent)))
5401 q=cache_info->pixels+offset*cache_info->number_channels;
5402 for (y=0; y < (ssize_t) rows; y++)
5404 (void) memcpy(q,p,(size_t) length);
5405 p+=nexus_info->region.width*cache_info->number_channels;
5406 q+=cache_info->columns*cache_info->number_channels;
5413 Write pixels to disk.
5415 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5417 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5418 cache_info->cache_filename);
5419 return(MagickFalse);
5421 if ((cache_info->columns == nexus_info->region.width) &&
5422 (extent <= MagickMaxBufferExtent))
5427 for (y=0; y < (ssize_t) rows; y++)
5429 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5430 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5432 if ((MagickSizeType) count != length)
5434 p+=nexus_info->region.width*cache_info->number_channels;
5435 offset+=cache_info->columns;
5437 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5438 (void) ClosePixelCacheOnDisk(cache_info);
5439 if (y < (ssize_t) rows)
5441 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5442 cache_info->cache_filename);
5443 return(MagickFalse);
5450 if ((cache_info->debug != MagickFalse) &&
5451 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5452 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5453 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5454 nexus_info->region.width,(double) nexus_info->region.height,(double)
5455 nexus_info->region.x,(double) nexus_info->region.y);