2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/exception.h"
52 #include "MagickCore/exception-private.h"
53 #include "MagickCore/geometry.h"
54 #include "MagickCore/list.h"
55 #include "MagickCore/log.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/memory-private.h"
59 #include "MagickCore/nt-base-private.h"
60 #include "MagickCore/pixel.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/policy.h"
63 #include "MagickCore/quantum.h"
64 #include "MagickCore/random_.h"
65 #include "MagickCore/resource_.h"
66 #include "MagickCore/semaphore.h"
67 #include "MagickCore/splay-tree.h"
68 #include "MagickCore/string_.h"
69 #include "MagickCore/string-private.h"
70 #include "MagickCore/thread-private.h"
71 #include "MagickCore/utility.h"
72 #include "MagickCore/utility-private.h"
73 #if defined(MAGICKCORE_ZLIB_DELEGATE)
80 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
81 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
82 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
87 typedef struct _MagickModulo
117 Forward declarations.
119 #if defined(__cplusplus) || defined(c_plusplus)
124 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
128 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
129 const ssize_t,const size_t,const size_t,ExceptionInfo *),
130 *GetVirtualPixelsCache(const Image *);
133 *GetVirtualMetacontentFromCache(const Image *);
135 static MagickBooleanType
136 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
138 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
139 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
140 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
141 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
142 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
143 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
144 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
145 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
148 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
149 const size_t,ExceptionInfo *),
150 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
151 const size_t,ExceptionInfo *),
152 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
153 NexusInfo *,ExceptionInfo *) magick_hot_spot;
155 #if defined(__cplusplus) || defined(c_plusplus)
162 static volatile MagickBooleanType
163 instantiate_cache = MagickFalse;
166 *cache_semaphore = (SemaphoreInfo *) NULL;
169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173 + A c q u i r e P i x e l C a c h e %
177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
179 % AcquirePixelCache() acquires a pixel cache.
181 % The format of the AcquirePixelCache() method is:
183 % Cache AcquirePixelCache(const size_t number_threads)
185 % A description of each parameter follows:
187 % o number_threads: the number of nexus threads.
190 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
195 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
196 if (cache_info == (CacheInfo *) NULL)
197 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
198 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
199 cache_info->type=UndefinedCache;
200 cache_info->mode=IOMode;
201 cache_info->colorspace=sRGBColorspace;
202 cache_info->file=(-1);
203 cache_info->id=GetMagickThreadId();
204 cache_info->number_threads=number_threads;
205 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
206 cache_info->number_threads=GetOpenMPMaximumThreads();
207 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
208 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
209 if (cache_info->number_threads == 0)
210 cache_info->number_threads=1;
211 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
212 if (cache_info->nexus_info == (NexusInfo **) NULL)
213 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
214 cache_info->semaphore=AllocateSemaphoreInfo();
215 cache_info->reference_count=1;
216 cache_info->file_semaphore=AllocateSemaphoreInfo();
217 cache_info->debug=IsEventLogging();
218 cache_info->signature=MagickSignature;
219 return((Cache ) cache_info);
223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227 % A c q u i r e P i x e l C a c h e N e x u s %
231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
235 % The format of the AcquirePixelCacheNexus method is:
237 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
239 % A description of each parameter follows:
241 % o number_threads: the number of nexus threads.
244 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
252 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
253 number_threads,sizeof(*nexus_info)));
254 if (nexus_info == (NexusInfo **) NULL)
255 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
256 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
257 sizeof(**nexus_info));
258 if (nexus_info[0] == (NexusInfo *) NULL)
259 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
260 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
261 for (i=0; i < (ssize_t) number_threads; i++)
263 nexus_info[i]=(&nexus_info[0][i]);
264 nexus_info[i]->signature=MagickSignature;
270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 + A c q u i r e P i x e l C a c h e P i x e l s %
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 % AcquirePixelCachePixels() returns the pixels associated with the specified
283 % The format of the AcquirePixelCachePixels() method is:
285 % const void *AcquirePixelCachePixels(const Image *image,
286 % MagickSizeType *length,ExceptionInfo *exception)
288 % A description of each parameter follows:
290 % o image: the image.
292 % o length: the pixel cache length.
294 % o exception: return any errors or warnings in this structure.
297 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
298 MagickSizeType *length,ExceptionInfo *exception)
303 assert(image != (const Image *) NULL);
304 assert(image->signature == MagickSignature);
305 assert(exception != (ExceptionInfo *) NULL);
306 assert(exception->signature == MagickSignature);
307 assert(image->cache != (Cache) NULL);
308 cache_info=(CacheInfo *) image->cache;
309 assert(cache_info->signature == MagickSignature);
311 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
312 return((const void *) NULL);
313 *length=cache_info->length;
314 return((const void *) cache_info->pixels);
318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322 + C a c h e C o m p o n e n t G e n e s i s %
326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328 % CacheComponentGenesis() instantiates the cache component.
330 % The format of the CacheComponentGenesis method is:
332 % MagickBooleanType CacheComponentGenesis(void)
335 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
337 AcquireSemaphoreInfo(&cache_semaphore);
342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 + C a c h e C o m p o n e n t T e r m i n u s %
350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
352 % CacheComponentTerminus() destroys the cache component.
354 % The format of the CacheComponentTerminus() method is:
356 % CacheComponentTerminus(void)
359 MagickPrivate void CacheComponentTerminus(void)
361 if (cache_semaphore == (SemaphoreInfo *) NULL)
362 AcquireSemaphoreInfo(&cache_semaphore);
363 LockSemaphoreInfo(cache_semaphore);
364 instantiate_cache=MagickFalse;
365 UnlockSemaphoreInfo(cache_semaphore);
366 DestroySemaphoreInfo(&cache_semaphore);
370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 + C l o n e P i x e l C a c h e %
378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380 % ClonePixelCache() clones a pixel cache.
382 % The format of the ClonePixelCache() method is:
384 % Cache ClonePixelCache(const Cache cache)
386 % A description of each parameter follows:
388 % o cache: the pixel cache.
391 MagickPrivate Cache ClonePixelCache(const Cache cache)
399 assert(cache != NULL);
400 cache_info=(const CacheInfo *) cache;
401 assert(cache_info->signature == MagickSignature);
402 if (cache_info->debug != MagickFalse)
403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
404 cache_info->filename);
405 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
406 if (clone_info == (Cache) NULL)
407 return((Cache) NULL);
408 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
409 return((Cache ) clone_info);
413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
417 + C l o n e P i x e l C a c h e P i x e l s %
421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
422 % ClonePixelCachePixels() clones the source pixel cache to the destination
425 % The format of the ClonePixelCachePixels() method is:
427 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
428 % CacheInfo *source_info,ExceptionInfo *exception)
430 % A description of each parameter follows:
432 % o cache_info: the pixel cache.
434 % o source_info: the source pixel cache.
436 % o exception: return any errors or warnings in this structure.
440 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
446 if (cache_info->file != -1)
448 status=close(cache_info->file);
449 cache_info->file=(-1);
450 RelinquishMagickResource(FileResource,1);
452 return(status == -1 ? MagickFalse : MagickTrue);
455 static inline MagickSizeType MagickMax(const MagickSizeType x,
456 const MagickSizeType y)
463 static inline MagickSizeType MagickMin(const MagickSizeType x,
464 const MagickSizeType y)
471 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
478 Open pixel cache on disk.
480 if (cache_info->file != -1)
481 return(MagickTrue); /* cache already open */
482 if (*cache_info->cache_filename == '\0')
483 file=AcquireUniqueFileResource(cache_info->cache_filename);
489 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
494 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
495 O_BINARY | O_EXCL,S_MODE);
497 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
503 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
506 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
512 (void) AcquireMagickResource(FileResource,1);
513 cache_info->file=file;
514 cache_info->mode=mode;
518 static inline MagickOffsetType ReadPixelCacheRegion(
519 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
520 const MagickSizeType length,unsigned char *restrict buffer)
522 register MagickOffsetType
528 #if !defined(MAGICKCORE_HAVE_PREAD)
529 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
530 return((MagickOffsetType) -1);
533 for (i=0; i < (MagickOffsetType) length; i+=count)
535 #if !defined(MAGICKCORE_HAVE_PREAD)
536 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
537 (MagickSizeType) SSIZE_MAX));
539 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
540 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
552 static inline MagickOffsetType WritePixelCacheRegion(
553 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
554 const MagickSizeType length,const unsigned char *restrict buffer)
556 register MagickOffsetType
562 #if !defined(MAGICKCORE_HAVE_PWRITE)
563 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
564 return((MagickOffsetType) -1);
567 for (i=0; i < (MagickOffsetType) length; i+=count)
569 #if !defined(MAGICKCORE_HAVE_PWRITE)
570 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
571 (MagickSizeType) SSIZE_MAX));
573 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
574 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
586 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
587 CacheInfo *cache_info,ExceptionInfo *exception)
592 register MagickOffsetType
602 Clone pixel cache (both caches on disk).
604 if (cache_info->debug != MagickFalse)
605 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
606 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
608 if (blob == (unsigned char *) NULL)
610 (void) ThrowMagickException(exception,GetMagickModule(),
611 ResourceLimitError,"MemoryAllocationFailed","'%s'",
612 cache_info->filename);
615 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
617 blob=(unsigned char *) RelinquishMagickMemory(blob);
618 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
619 cache_info->cache_filename);
622 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
624 (void) ClosePixelCacheOnDisk(cache_info);
625 blob=(unsigned char *) RelinquishMagickMemory(blob);
626 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
627 clone_info->cache_filename);
631 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
633 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
634 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
638 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
639 cache_info->cache_filename);
642 length=(size_t) count;
643 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
644 if ((MagickSizeType) count != length)
646 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
647 clone_info->cache_filename);
651 (void) ClosePixelCacheOnDisk(clone_info);
652 (void) ClosePixelCacheOnDisk(cache_info);
653 blob=(unsigned char *) RelinquishMagickMemory(blob);
654 if (i < (MagickOffsetType) cache_info->length)
659 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
660 CacheInfo *cache_info,ExceptionInfo *exception)
665 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
668 Clone pixel cache (both caches in memory).
670 if (cache_info->debug != MagickFalse)
671 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
672 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
676 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
679 Clone pixel cache (one cache on disk, one in memory).
681 if (cache_info->debug != MagickFalse)
682 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
683 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
685 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
686 cache_info->cache_filename);
689 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
690 cache_info->length,(unsigned char *) clone_info->pixels);
691 (void) ClosePixelCacheOnDisk(cache_info);
692 if ((MagickSizeType) count != cache_info->length)
694 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
695 cache_info->cache_filename);
700 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
703 Clone pixel cache (one cache on disk, one in memory).
705 if (clone_info->debug != MagickFalse)
706 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
707 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
709 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
710 clone_info->cache_filename);
713 count=WritePixelCacheRegion(clone_info,clone_info->offset,
714 clone_info->length,(unsigned char *) cache_info->pixels);
715 (void) ClosePixelCacheOnDisk(clone_info);
716 if ((MagickSizeType) count != clone_info->length)
718 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
719 clone_info->cache_filename);
725 Clone pixel cache (both caches on disk).
727 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
730 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
731 CacheInfo *cache_info,ExceptionInfo *exception)
744 register unsigned char
757 Clone pixel cache (unoptimized).
759 if (cache_info->debug != MagickFalse)
761 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
762 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
764 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
765 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
767 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
768 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
770 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
772 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
773 clone_info->number_channels)*sizeof(Quantum),MagickMax(
774 cache_info->metacontent_extent,clone_info->metacontent_extent));
775 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
776 if (blob == (unsigned char *) NULL)
778 (void) ThrowMagickException(exception,GetMagickModule(),
779 ResourceLimitError,"MemoryAllocationFailed","'%s'",
780 cache_info->filename);
783 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
786 if (cache_info->type == DiskCache)
788 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
790 blob=(unsigned char *) RelinquishMagickMemory(blob);
791 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
792 cache_info->cache_filename);
795 cache_offset=cache_info->offset;
797 if (clone_info->type == DiskCache)
799 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
801 blob=(unsigned char *) RelinquishMagickMemory(blob);
802 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
803 clone_info->cache_filename);
806 clone_offset=clone_info->offset;
809 Clone pixel channels.
813 for (y=0; y < (ssize_t) cache_info->rows; y++)
815 for (x=0; x < (ssize_t) cache_info->columns; x++)
821 Read a set of pixel channels.
823 length=cache_info->number_channels*sizeof(Quantum);
824 if (cache_info->type != DiskCache)
825 p=(unsigned char *) cache_info->pixels+cache_offset;
828 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
829 if ((MagickSizeType) count != length)
835 cache_offset+=length;
836 if ((y < (ssize_t) clone_info->rows) &&
837 (x < (ssize_t) clone_info->columns))
838 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
850 Write a set of pixel channels.
852 channel=clone_info->channel_map[i].channel;
853 traits=cache_info->channel_map[channel].traits;
854 if (traits == UndefinedPixelTrait)
856 clone_offset+=sizeof(Quantum);
859 offset=cache_info->channel_map[channel].offset;
860 if (clone_info->type != DiskCache)
861 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
862 offset*sizeof(Quantum),sizeof(Quantum));
865 count=WritePixelCacheRegion(clone_info,clone_offset,
866 sizeof(Quantum),p+offset*sizeof(Quantum));
867 if ((MagickSizeType) count != sizeof(Quantum))
873 clone_offset+=sizeof(Quantum);
876 if (y < (ssize_t) clone_info->rows)
879 Set remaining columns as undefined.
881 length=clone_info->number_channels*sizeof(Quantum);
882 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
883 for ( ; x < (ssize_t) clone_info->columns; x++)
885 if (clone_info->type != DiskCache)
886 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
890 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
891 if ((MagickSizeType) count != length)
897 clone_offset+=length;
901 length=clone_info->number_channels*sizeof(Quantum);
902 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
903 for ( ; y < (ssize_t) clone_info->rows; y++)
906 Set remaining rows as undefined.
908 for (x=0; x < (ssize_t) clone_info->columns; x++)
910 if (clone_info->type != DiskCache)
911 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
915 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
916 if ((MagickSizeType) count != length)
922 clone_offset+=length;
925 if ((cache_info->metacontent_extent != 0) ||
926 (clone_info->metacontent_extent != 0))
931 for (y=0; y < (ssize_t) cache_info->rows; y++)
933 for (x=0; x < (ssize_t) cache_info->columns; x++)
936 Read a set of metacontent.
938 length=cache_info->metacontent_extent;
939 if (cache_info->type != DiskCache)
940 p=(unsigned char *) cache_info->pixels+cache_offset;
943 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
944 if ((MagickSizeType) count != length)
950 cache_offset+=length;
951 if ((y < (ssize_t) clone_info->rows) &&
952 (x < (ssize_t) clone_info->columns))
955 Write a set of metacontent.
957 length=clone_info->metacontent_extent;
958 if (clone_info->type != DiskCache)
959 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
963 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
964 if ((MagickSizeType) count != length)
970 clone_offset+=length;
973 length=clone_info->metacontent_extent;
974 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
975 for ( ; x < (ssize_t) clone_info->columns; x++)
978 Set remaining columns as undefined.
980 if (clone_info->type != DiskCache)
981 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
985 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
986 if ((MagickSizeType) count != length)
992 clone_offset+=length;
995 if (y < (ssize_t) clone_info->rows)
998 Set remaining rows as undefined.
1000 length=clone_info->metacontent_extent;
1001 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1002 for ( ; y < (ssize_t) clone_info->rows; y++)
1004 for (x=0; x < (ssize_t) clone_info->columns; x++)
1006 if (clone_info->type != DiskCache)
1007 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1011 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1013 if ((MagickSizeType) count != length)
1019 clone_offset+=length;
1024 if (clone_info->type == DiskCache)
1025 (void) ClosePixelCacheOnDisk(clone_info);
1026 if (cache_info->type == DiskCache)
1027 (void) ClosePixelCacheOnDisk(cache_info);
1028 blob=(unsigned char *) RelinquishMagickMemory(blob);
1032 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1033 CacheInfo *cache_info,ExceptionInfo *exception)
1039 if (cache_info->type == PingCache)
1041 p=cache_info->channel_map;
1042 q=clone_info->channel_map;
1043 if ((cache_info->columns == clone_info->columns) &&
1044 (cache_info->rows == clone_info->rows) &&
1045 (cache_info->number_channels == clone_info->number_channels) &&
1046 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1047 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1048 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1049 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1057 + C l o n e P i x e l C a c h e M e t h o d s %
1061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1063 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1066 % The format of the ClonePixelCacheMethods() method is:
1068 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1070 % A description of each parameter follows:
1072 % o clone: Specifies a pointer to a Cache structure.
1074 % o cache: the pixel cache.
1077 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1083 assert(clone != (Cache) NULL);
1084 source_info=(CacheInfo *) clone;
1085 assert(source_info->signature == MagickSignature);
1086 if (source_info->debug != MagickFalse)
1087 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1088 source_info->filename);
1089 assert(cache != (Cache) NULL);
1090 cache_info=(CacheInfo *) cache;
1091 assert(cache_info->signature == MagickSignature);
1092 source_info->methods=cache_info->methods;
1096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1100 + D e s t r o y I m a g e P i x e l C a c h e %
1104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1106 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1108 % The format of the DestroyImagePixelCache() method is:
1110 % void DestroyImagePixelCache(Image *image)
1112 % A description of each parameter follows:
1114 % o image: the image.
1117 static void DestroyImagePixelCache(Image *image)
1119 assert(image != (Image *) NULL);
1120 assert(image->signature == MagickSignature);
1121 if (image->debug != MagickFalse)
1122 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1123 if (image->cache == (void *) NULL)
1125 image->cache=DestroyPixelCache(image->cache);
1129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1133 + D e s t r o y I m a g e P i x e l s %
1137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1139 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1141 % The format of the DestroyImagePixels() method is:
1143 % void DestroyImagePixels(Image *image)
1145 % A description of each parameter follows:
1147 % o image: the image.
1150 MagickExport void DestroyImagePixels(Image *image)
1155 assert(image != (const Image *) NULL);
1156 assert(image->signature == MagickSignature);
1157 if (image->debug != MagickFalse)
1158 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1159 assert(image->cache != (Cache) NULL);
1160 cache_info=(CacheInfo *) image->cache;
1161 assert(cache_info->signature == MagickSignature);
1162 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1164 cache_info->methods.destroy_pixel_handler(image);
1167 image->cache=DestroyPixelCache(image->cache);
1171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1175 + D e s t r o y P i x e l C a c h e %
1179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1181 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1183 % The format of the DestroyPixelCache() method is:
1185 % Cache DestroyPixelCache(Cache cache)
1187 % A description of each parameter follows:
1189 % o cache: the pixel cache.
1193 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1195 switch (cache_info->type)
1199 if (cache_info->mapped == MagickFalse)
1200 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
1201 cache_info->pixels);
1203 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1204 (size_t) cache_info->length);
1205 RelinquishMagickResource(MemoryResource,cache_info->length);
1210 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1211 cache_info->length);
1212 RelinquishMagickResource(MapResource,cache_info->length);
1216 if (cache_info->file != -1)
1217 (void) ClosePixelCacheOnDisk(cache_info);
1218 RelinquishMagickResource(DiskResource,cache_info->length);
1224 cache_info->type=UndefinedCache;
1225 cache_info->mapped=MagickFalse;
1226 cache_info->metacontent=(void *) NULL;
1229 MagickPrivate Cache DestroyPixelCache(Cache cache)
1234 assert(cache != (Cache) NULL);
1235 cache_info=(CacheInfo *) cache;
1236 assert(cache_info->signature == MagickSignature);
1237 if (cache_info->debug != MagickFalse)
1238 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1239 cache_info->filename);
1240 LockSemaphoreInfo(cache_info->semaphore);
1241 cache_info->reference_count--;
1242 if (cache_info->reference_count != 0)
1244 UnlockSemaphoreInfo(cache_info->semaphore);
1245 return((Cache) NULL);
1247 UnlockSemaphoreInfo(cache_info->semaphore);
1248 if (cache_info->debug != MagickFalse)
1251 message[MaxTextExtent];
1253 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1254 cache_info->filename);
1255 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1257 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1258 (cache_info->type != DiskCache)))
1259 RelinquishPixelCachePixels(cache_info);
1262 RelinquishPixelCachePixels(cache_info);
1263 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1265 *cache_info->cache_filename='\0';
1266 if (cache_info->nexus_info != (NexusInfo **) NULL)
1267 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1268 cache_info->number_threads);
1269 if (cache_info->random_info != (RandomInfo *) NULL)
1270 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1271 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
1272 DestroySemaphoreInfo(&cache_info->file_semaphore);
1273 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1274 DestroySemaphoreInfo(&cache_info->semaphore);
1275 cache_info->signature=(~MagickSignature);
1276 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1286 + D e s t r o y P i x e l C a c h e N e x u s %
1290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1292 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1294 % The format of the DestroyPixelCacheNexus() method is:
1296 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1297 % const size_t number_threads)
1299 % A description of each parameter follows:
1301 % o nexus_info: the nexus to destroy.
1303 % o number_threads: the number of nexus threads.
1307 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1309 if (nexus_info->mapped == MagickFalse)
1310 (void) RelinquishAlignedMemory(nexus_info->cache);
1312 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1313 nexus_info->cache=(Quantum *) NULL;
1314 nexus_info->pixels=(Quantum *) NULL;
1315 nexus_info->metacontent=(void *) NULL;
1316 nexus_info->length=0;
1317 nexus_info->mapped=MagickFalse;
1320 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1321 const size_t number_threads)
1326 assert(nexus_info != (NexusInfo **) NULL);
1327 for (i=0; i < (ssize_t) number_threads; i++)
1329 if (nexus_info[i]->cache != (Quantum *) NULL)
1330 RelinquishCacheNexusPixels(nexus_info[i]);
1331 nexus_info[i]->signature=(~MagickSignature);
1333 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1334 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1343 % G e t A u t h e n t i c M e t a c o n t e n t %
1347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1349 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1350 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1351 % returned if the associated pixels are not available.
1353 % The format of the GetAuthenticMetacontent() method is:
1355 % void *GetAuthenticMetacontent(const Image *image)
1357 % A description of each parameter follows:
1359 % o image: the image.
1362 MagickExport void *GetAuthenticMetacontent(const Image *image)
1368 id = GetOpenMPThreadId();
1373 assert(image != (const Image *) NULL);
1374 assert(image->signature == MagickSignature);
1375 assert(image->cache != (Cache) NULL);
1376 cache_info=(CacheInfo *) image->cache;
1377 assert(cache_info->signature == MagickSignature);
1378 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1379 (GetAuthenticMetacontentFromHandler) NULL)
1381 metacontent=cache_info->methods.
1382 get_authentic_metacontent_from_handler(image);
1383 return(metacontent);
1385 assert(id < (int) cache_info->number_threads);
1386 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1387 cache_info->nexus_info[id]);
1388 return(metacontent);
1392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396 + 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 %
1400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1403 % with the last call to QueueAuthenticPixelsCache() or
1404 % GetAuthenticPixelsCache().
1406 % The format of the GetAuthenticMetacontentFromCache() method is:
1408 % void *GetAuthenticMetacontentFromCache(const Image *image)
1410 % A description of each parameter follows:
1412 % o image: the image.
1415 static void *GetAuthenticMetacontentFromCache(const Image *image)
1421 id = GetOpenMPThreadId();
1426 assert(image != (const Image *) NULL);
1427 assert(image->signature == MagickSignature);
1428 assert(image->cache != (Cache) NULL);
1429 cache_info=(CacheInfo *) image->cache;
1430 assert(cache_info->signature == MagickSignature);
1431 assert(id < (int) cache_info->number_threads);
1432 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1433 cache_info->nexus_info[id]);
1434 return(metacontent);
1438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1442 + 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 %
1446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1448 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1449 % disk pixel cache as defined by the geometry parameters. A pointer to the
1450 % pixels is returned if the pixels are transferred, otherwise a NULL is
1453 % The format of the GetAuthenticPixelCacheNexus() method is:
1455 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1456 % const ssize_t y,const size_t columns,const size_t rows,
1457 % NexusInfo *nexus_info,ExceptionInfo *exception)
1459 % A description of each parameter follows:
1461 % o image: the image.
1463 % o x,y,columns,rows: These values define the perimeter of a region of
1466 % o nexus_info: the cache nexus to return.
1468 % o exception: return any errors or warnings in this structure.
1472 static inline MagickBooleanType IsPixelAuthentic(
1473 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1481 if (cache_info->type == PingCache)
1483 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1484 nexus_info->region.x;
1485 status=nexus_info->pixels == (cache_info->pixels+offset*
1486 cache_info->number_channels) ? MagickTrue : MagickFalse;
1490 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1491 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1492 NexusInfo *nexus_info,ExceptionInfo *exception)
1501 Transfer pixels from the cache.
1503 assert(image != (Image *) NULL);
1504 assert(image->signature == MagickSignature);
1505 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1507 if (q == (Quantum *) NULL)
1508 return((Quantum *) NULL);
1509 cache_info=(CacheInfo *) image->cache;
1510 assert(cache_info->signature == MagickSignature);
1511 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1513 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1514 return((Quantum *) NULL);
1515 if (cache_info->metacontent_extent != 0)
1516 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1517 return((Quantum *) NULL);
1522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1526 + 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 %
1530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1532 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1533 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1535 % The format of the GetAuthenticPixelsFromCache() method is:
1537 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1539 % A description of each parameter follows:
1541 % o image: the image.
1544 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1550 id = GetOpenMPThreadId();
1552 assert(image != (const Image *) NULL);
1553 assert(image->signature == MagickSignature);
1554 assert(image->cache != (Cache) NULL);
1555 cache_info=(CacheInfo *) image->cache;
1556 assert(cache_info->signature == MagickSignature);
1557 assert(id < (int) cache_info->number_threads);
1558 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1566 % G e t A u t h e n t i c P i x e l Q u e u e %
1570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1572 % GetAuthenticPixelQueue() returns the authentic pixels associated
1573 % corresponding with the last call to QueueAuthenticPixels() or
1574 % GetAuthenticPixels().
1576 % The format of the GetAuthenticPixelQueue() method is:
1578 % Quantum *GetAuthenticPixelQueue(const Image image)
1580 % A description of each parameter follows:
1582 % o image: the image.
1585 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1591 id = GetOpenMPThreadId();
1593 assert(image != (const Image *) NULL);
1594 assert(image->signature == MagickSignature);
1595 assert(image->cache != (Cache) NULL);
1596 cache_info=(CacheInfo *) image->cache;
1597 assert(cache_info->signature == MagickSignature);
1598 if (cache_info->methods.get_authentic_pixels_from_handler !=
1599 (GetAuthenticPixelsFromHandler) NULL)
1600 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1601 assert(id < (int) cache_info->number_threads);
1602 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1610 % G e t A u t h e n t i c P i x e l s %
1613 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1616 % region is successfully accessed, a pointer to a Quantum array
1617 % representing the region is returned, otherwise NULL is returned.
1619 % The returned pointer may point to a temporary working copy of the pixels
1620 % or it may point to the original pixels in memory. Performance is maximized
1621 % if the selected region is part of one row, or one or more full rows, since
1622 % then there is opportunity to access the pixels in-place (without a copy)
1623 % if the image is in memory, or in a memory-mapped file. The returned pointer
1624 % must *never* be deallocated by the user.
1626 % Pixels accessed via the returned pointer represent a simple array of type
1627 % Quantum. If the image has corresponding metacontent,call
1628 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1629 % meta-content corresponding to the region. Once the Quantum array has
1630 % been updated, the changes must be saved back to the underlying image using
1631 % SyncAuthenticPixels() or they may be lost.
1633 % The format of the GetAuthenticPixels() method is:
1635 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1636 % const ssize_t y,const size_t columns,const size_t rows,
1637 % ExceptionInfo *exception)
1639 % A description of each parameter follows:
1641 % o image: the image.
1643 % o x,y,columns,rows: These values define the perimeter of a region of
1646 % o exception: return any errors or warnings in this structure.
1649 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1650 const ssize_t y,const size_t columns,const size_t rows,
1651 ExceptionInfo *exception)
1657 id = GetOpenMPThreadId();
1662 assert(image != (Image *) NULL);
1663 assert(image->signature == MagickSignature);
1664 assert(image->cache != (Cache) NULL);
1665 cache_info=(CacheInfo *) image->cache;
1666 assert(cache_info->signature == MagickSignature);
1667 if (cache_info->methods.get_authentic_pixels_handler !=
1668 (GetAuthenticPixelsHandler) NULL)
1670 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1674 assert(id < (int) cache_info->number_threads);
1675 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1676 cache_info->nexus_info[id],exception);
1681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685 + G e t A u t h e n t i c P i x e l s C a c h e %
1689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1691 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1692 % as defined by the geometry parameters. A pointer to the pixels is returned
1693 % if the pixels are transferred, otherwise a NULL is returned.
1695 % The format of the GetAuthenticPixelsCache() method is:
1697 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1698 % const ssize_t y,const size_t columns,const size_t rows,
1699 % ExceptionInfo *exception)
1701 % A description of each parameter follows:
1703 % o image: the image.
1705 % o x,y,columns,rows: These values define the perimeter of a region of
1708 % o exception: return any errors or warnings in this structure.
1711 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1712 const ssize_t y,const size_t columns,const size_t rows,
1713 ExceptionInfo *exception)
1719 id = GetOpenMPThreadId();
1724 assert(image != (const Image *) NULL);
1725 assert(image->signature == MagickSignature);
1726 assert(image->cache != (Cache) NULL);
1727 cache_info=(CacheInfo *) image->cache;
1728 if (cache_info == (Cache) NULL)
1729 return((Quantum *) NULL);
1730 assert(cache_info->signature == MagickSignature);
1731 assert(id < (int) cache_info->number_threads);
1732 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1733 cache_info->nexus_info[id],exception);
1738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1742 + G e t I m a g e E x t e n t %
1746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1748 % GetImageExtent() returns the extent of the pixels associated corresponding
1749 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1751 % The format of the GetImageExtent() method is:
1753 % MagickSizeType GetImageExtent(const Image *image)
1755 % A description of each parameter follows:
1757 % o image: the image.
1760 MagickExport MagickSizeType GetImageExtent(const Image *image)
1766 id = GetOpenMPThreadId();
1768 assert(image != (Image *) NULL);
1769 assert(image->signature == MagickSignature);
1770 if (image->debug != MagickFalse)
1771 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1772 assert(image->cache != (Cache) NULL);
1773 cache_info=(CacheInfo *) image->cache;
1774 assert(cache_info->signature == MagickSignature);
1775 assert(id < (int) cache_info->number_threads);
1776 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1784 + G e t I m a g e P i x e l C a c h e %
1788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1790 % GetImagePixelCache() ensures that there is only a single reference to the
1791 % pixel cache to be modified, updating the provided cache pointer to point to
1792 % a clone of the original pixel cache if necessary.
1794 % The format of the GetImagePixelCache method is:
1796 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1797 % ExceptionInfo *exception)
1799 % A description of each parameter follows:
1801 % o image: the image.
1803 % o clone: any value other than MagickFalse clones the cache pixels.
1805 % o exception: return any errors or warnings in this structure.
1809 static inline MagickBooleanType ValidatePixelCacheMorphology(
1810 const Image *restrict image)
1813 *restrict cache_info;
1815 const PixelChannelMap
1820 Does the image match the pixel cache morphology?
1822 cache_info=(CacheInfo *) image->cache;
1823 p=image->channel_map;
1824 q=cache_info->channel_map;
1825 if ((image->storage_class != cache_info->storage_class) ||
1826 (image->colorspace != cache_info->colorspace) ||
1827 (image->alpha_trait != cache_info->alpha_trait) ||
1828 (image->mask != cache_info->mask) ||
1829 (image->columns != cache_info->columns) ||
1830 (image->rows != cache_info->rows) ||
1831 (image->number_channels != cache_info->number_channels) ||
1832 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1833 (image->metacontent_extent != cache_info->metacontent_extent) ||
1834 (cache_info->nexus_info == (NexusInfo **) NULL))
1835 return(MagickFalse);
1839 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1840 ExceptionInfo *exception)
1849 static MagickSizeType
1855 cache_timestamp = 0;
1858 LockSemaphoreInfo(image->semaphore);
1859 if (cpu_throttle == 0)
1865 Set CPU throttle in milleseconds.
1867 cpu_throttle=MagickResourceInfinity;
1868 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1869 if (limit == (char *) NULL)
1870 limit=GetPolicyValue("throttle");
1871 if (limit != (char *) NULL)
1873 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1874 limit=DestroyString(limit);
1877 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1878 MagickDelay(cpu_throttle);
1879 if (time_limit == 0)
1882 Set the expire time in seconds.
1884 time_limit=GetMagickResourceLimit(TimeResource);
1885 cache_timestamp=time((time_t *) NULL);
1887 if ((time_limit != MagickResourceInfinity) &&
1888 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1889 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1890 assert(image->cache != (Cache) NULL);
1891 cache_info=(CacheInfo *) image->cache;
1892 destroy=MagickFalse;
1893 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1895 LockSemaphoreInfo(cache_info->semaphore);
1896 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1907 clone_image=(*image);
1908 clone_image.semaphore=AllocateSemaphoreInfo();
1909 clone_image.reference_count=1;
1910 clone_image.cache=ClonePixelCache(cache_info);
1911 clone_info=(CacheInfo *) clone_image.cache;
1912 status=OpenPixelCache(&clone_image,IOMode,exception);
1913 if (status != MagickFalse)
1915 if (clone != MagickFalse)
1916 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1917 if (status != MagickFalse)
1919 if (cache_info->reference_count == 1)
1920 cache_info->nexus_info=(NexusInfo **) NULL;
1922 image->cache=clone_image.cache;
1925 DestroySemaphoreInfo(&clone_image.semaphore);
1927 UnlockSemaphoreInfo(cache_info->semaphore);
1929 if (destroy != MagickFalse)
1930 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1931 if (status != MagickFalse)
1934 Ensure the image matches the pixel cache morphology.
1936 image->taint=MagickTrue;
1937 image->type=UndefinedType;
1938 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1940 status=OpenPixelCache(image,IOMode,exception);
1941 cache_info=(CacheInfo *) image->cache;
1942 if (cache_info->type == DiskCache)
1943 (void) ClosePixelCacheOnDisk(cache_info);
1946 UnlockSemaphoreInfo(image->semaphore);
1947 if (status == MagickFalse)
1948 return((Cache) NULL);
1949 return(image->cache);
1953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1957 + G e t I m a g e P i x e l C a c h e T y p e %
1961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1963 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1964 % DiskCache, MemoryCache, MapCache, or PingCache.
1966 % The format of the GetImagePixelCacheType() method is:
1968 % CacheType GetImagePixelCacheType(const Image *image)
1970 % A description of each parameter follows:
1972 % o image: the image.
1975 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1980 assert(image != (Image *) NULL);
1981 assert(image->signature == MagickSignature);
1982 assert(image->cache != (Cache) NULL);
1983 cache_info=(CacheInfo *) image->cache;
1984 assert(cache_info->signature == MagickSignature);
1985 return(cache_info->type);
1989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1993 % G e t O n e A u t h e n t i c P i x e l %
1997 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2000 % location. The image background color is returned if an error occurs.
2002 % The format of the GetOneAuthenticPixel() method is:
2004 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2005 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2007 % A description of each parameter follows:
2009 % o image: the image.
2011 % o x,y: These values define the location of the pixel to return.
2013 % o pixel: return a pixel at the specified (x,y) location.
2015 % o exception: return any errors or warnings in this structure.
2018 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2019 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2030 assert(image != (Image *) NULL);
2031 assert(image->signature == MagickSignature);
2032 assert(image->cache != (Cache) NULL);
2033 cache_info=(CacheInfo *) image->cache;
2034 assert(cache_info->signature == MagickSignature);
2035 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2036 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2037 (GetOneAuthenticPixelFromHandler) NULL)
2038 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2040 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2041 if (q == (Quantum *) NULL)
2043 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2044 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2045 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2046 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2047 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2048 return(MagickFalse);
2050 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2055 channel=GetPixelChannelChannel(image,i);
2056 pixel[channel]=q[i];
2062 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2066 + 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 %
2070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2072 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2073 % location. The image background color is returned if an error occurs.
2075 % The format of the GetOneAuthenticPixelFromCache() method is:
2077 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2078 % const ssize_t x,const ssize_t y,Quantum *pixel,
2079 % ExceptionInfo *exception)
2081 % A description of each parameter follows:
2083 % o image: the image.
2085 % o x,y: These values define the location of the pixel to return.
2087 % o pixel: return a pixel at the specified (x,y) location.
2089 % o exception: return any errors or warnings in this structure.
2092 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2093 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2099 id = GetOpenMPThreadId();
2107 assert(image != (const Image *) NULL);
2108 assert(image->signature == MagickSignature);
2109 assert(image->cache != (Cache) NULL);
2110 cache_info=(CacheInfo *) image->cache;
2111 assert(cache_info->signature == MagickSignature);
2112 assert(id < (int) cache_info->number_threads);
2113 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2114 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2116 if (q == (Quantum *) NULL)
2118 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2119 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2120 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2121 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2122 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2123 return(MagickFalse);
2125 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2130 channel=GetPixelChannelChannel(image,i);
2131 pixel[channel]=q[i];
2137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2141 % G e t O n e V i r t u a l P i x e l %
2145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2147 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2148 % (x,y) location. The image background color is returned if an error occurs.
2149 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2151 % The format of the GetOneVirtualPixel() method is:
2153 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2154 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2156 % A description of each parameter follows:
2158 % o image: the image.
2160 % o x,y: These values define the location of the pixel to return.
2162 % o pixel: return a pixel at the specified (x,y) location.
2164 % o exception: return any errors or warnings in this structure.
2167 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2168 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2174 id = GetOpenMPThreadId();
2182 assert(image != (const Image *) NULL);
2183 assert(image->signature == MagickSignature);
2184 assert(image->cache != (Cache) NULL);
2185 cache_info=(CacheInfo *) image->cache;
2186 assert(cache_info->signature == MagickSignature);
2187 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2188 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2189 (GetOneVirtualPixelFromHandler) NULL)
2190 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2191 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2192 assert(id < (int) cache_info->number_threads);
2193 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2194 1UL,1UL,cache_info->nexus_info[id],exception);
2195 if (p == (const Quantum *) NULL)
2197 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2198 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2199 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2200 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2201 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2202 return(MagickFalse);
2204 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2209 channel=GetPixelChannelChannel(image,i);
2210 pixel[channel]=p[i];
2216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2220 + 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 %
2224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2226 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2227 % specified (x,y) location. The image background color is returned if an
2230 % The format of the GetOneVirtualPixelFromCache() method is:
2232 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2233 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2234 % Quantum *pixel,ExceptionInfo *exception)
2236 % A description of each parameter follows:
2238 % o image: the image.
2240 % o virtual_pixel_method: the virtual pixel method.
2242 % o x,y: These values define the location of the pixel to return.
2244 % o pixel: return a pixel at the specified (x,y) location.
2246 % o exception: return any errors or warnings in this structure.
2249 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2250 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2251 Quantum *pixel,ExceptionInfo *exception)
2257 id = GetOpenMPThreadId();
2265 assert(image != (const Image *) NULL);
2266 assert(image->signature == MagickSignature);
2267 assert(image->cache != (Cache) NULL);
2268 cache_info=(CacheInfo *) image->cache;
2269 assert(cache_info->signature == MagickSignature);
2270 assert(id < (int) cache_info->number_threads);
2271 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2272 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2273 cache_info->nexus_info[id],exception);
2274 if (p == (const Quantum *) NULL)
2276 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2277 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2278 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2279 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2280 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2281 return(MagickFalse);
2283 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2288 channel=GetPixelChannelChannel(image,i);
2289 pixel[channel]=p[i];
2295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2299 % G e t O n e V i r t u a l P i x e l I n f o %
2303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2305 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2306 % location. The image background color is returned if an error occurs. If
2307 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2309 % The format of the GetOneVirtualPixelInfo() method is:
2311 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2312 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2313 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2315 % A description of each parameter follows:
2317 % o image: the image.
2319 % o virtual_pixel_method: the virtual pixel method.
2321 % o x,y: these values define the location of the pixel to return.
2323 % o pixel: return a pixel at the specified (x,y) location.
2325 % o exception: return any errors or warnings in this structure.
2328 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2329 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2330 PixelInfo *pixel,ExceptionInfo *exception)
2336 id = GetOpenMPThreadId();
2338 register const Quantum
2341 assert(image != (const Image *) NULL);
2342 assert(image->signature == MagickSignature);
2343 assert(image->cache != (Cache) NULL);
2344 cache_info=(CacheInfo *) image->cache;
2345 assert(cache_info->signature == MagickSignature);
2346 assert(id < (int) cache_info->number_threads);
2347 GetPixelInfo(image,pixel);
2348 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2349 cache_info->nexus_info[id],exception);
2350 if (p == (const Quantum *) NULL)
2351 return(MagickFalse);
2352 GetPixelInfoPixel(image,p,pixel);
2357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2361 + G e t P i x e l C a c h e C o l o r s p a c e %
2365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2367 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2369 % The format of the GetPixelCacheColorspace() method is:
2371 % Colorspace GetPixelCacheColorspace(Cache cache)
2373 % A description of each parameter follows:
2375 % o cache: the pixel cache.
2378 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2383 assert(cache != (Cache) NULL);
2384 cache_info=(CacheInfo *) cache;
2385 assert(cache_info->signature == MagickSignature);
2386 if (cache_info->debug != MagickFalse)
2387 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2388 cache_info->filename);
2389 return(cache_info->colorspace);
2393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2397 + G e t P i x e l C a c h e M e t h o d s %
2401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2403 % GetPixelCacheMethods() initializes the CacheMethods structure.
2405 % The format of the GetPixelCacheMethods() method is:
2407 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2409 % A description of each parameter follows:
2411 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2414 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2416 assert(cache_methods != (CacheMethods *) NULL);
2417 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2418 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2419 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2420 cache_methods->get_virtual_metacontent_from_handler=
2421 GetVirtualMetacontentFromCache;
2422 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2423 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2424 cache_methods->get_authentic_metacontent_from_handler=
2425 GetAuthenticMetacontentFromCache;
2426 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2427 cache_methods->get_one_authentic_pixel_from_handler=
2428 GetOneAuthenticPixelFromCache;
2429 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2430 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2431 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2439 + G e t P i x e l C a c h e N e x u s E x t e n t %
2443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2445 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2446 % corresponding with the last call to SetPixelCacheNexusPixels() or
2447 % GetPixelCacheNexusPixels().
2449 % The format of the GetPixelCacheNexusExtent() method is:
2451 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2452 % NexusInfo *nexus_info)
2454 % A description of each parameter follows:
2456 % o nexus_info: the nexus info.
2459 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2460 NexusInfo *nexus_info)
2468 assert(cache != NULL);
2469 cache_info=(CacheInfo *) cache;
2470 assert(cache_info->signature == MagickSignature);
2471 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2473 return((MagickSizeType) cache_info->columns*cache_info->rows);
2478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2482 + 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 %
2486 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2488 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2491 % The format of the GetPixelCacheNexusMetacontent() method is:
2493 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2494 % NexusInfo *nexus_info)
2496 % A description of each parameter follows:
2498 % o cache: the pixel cache.
2500 % o nexus_info: the cache nexus to return the meta-content.
2503 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2504 NexusInfo *nexus_info)
2509 assert(cache != NULL);
2510 cache_info=(CacheInfo *) cache;
2511 assert(cache_info->signature == MagickSignature);
2512 if (cache_info->storage_class == UndefinedClass)
2513 return((void *) NULL);
2514 return(nexus_info->metacontent);
2518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2522 + G e t P i x e l C a c h e N e x u s P i x e l s %
2526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2528 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2531 % The format of the GetPixelCacheNexusPixels() method is:
2533 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2534 % NexusInfo *nexus_info)
2536 % A description of each parameter follows:
2538 % o cache: the pixel cache.
2540 % o nexus_info: the cache nexus to return the pixels.
2543 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2544 NexusInfo *nexus_info)
2549 assert(cache != NULL);
2550 cache_info=(CacheInfo *) cache;
2551 assert(cache_info->signature == MagickSignature);
2552 if (cache_info->storage_class == UndefinedClass)
2553 return((Quantum *) NULL);
2554 return(nexus_info->pixels);
2558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2562 + G e t P i x e l C a c h e P i x e l s %
2566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2568 % GetPixelCachePixels() returns the pixels associated with the specified image.
2570 % The format of the GetPixelCachePixels() method is:
2572 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2573 % ExceptionInfo *exception)
2575 % A description of each parameter follows:
2577 % o image: the image.
2579 % o length: the pixel cache length.
2581 % o exception: return any errors or warnings in this structure.
2584 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2585 ExceptionInfo *exception)
2590 assert(image != (const Image *) NULL);
2591 assert(image->signature == MagickSignature);
2592 assert(image->cache != (Cache) NULL);
2593 assert(length != (MagickSizeType *) NULL);
2594 assert(exception != (ExceptionInfo *) NULL);
2595 assert(exception->signature == MagickSignature);
2596 cache_info=(CacheInfo *) image->cache;
2597 assert(cache_info->signature == MagickSignature);
2599 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2600 return((void *) NULL);
2601 *length=cache_info->length;
2602 return((void *) cache_info->pixels);
2606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2610 + 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 %
2614 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2616 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2618 % The format of the GetPixelCacheStorageClass() method is:
2620 % ClassType GetPixelCacheStorageClass(Cache cache)
2622 % A description of each parameter follows:
2624 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2626 % o cache: the pixel cache.
2629 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2634 assert(cache != (Cache) NULL);
2635 cache_info=(CacheInfo *) cache;
2636 assert(cache_info->signature == MagickSignature);
2637 if (cache_info->debug != MagickFalse)
2638 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2639 cache_info->filename);
2640 return(cache_info->storage_class);
2644 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2648 + G e t P i x e l C a c h e T i l e S i z e %
2652 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2654 % GetPixelCacheTileSize() returns the pixel cache tile size.
2656 % The format of the GetPixelCacheTileSize() method is:
2658 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2661 % A description of each parameter follows:
2663 % o image: the image.
2665 % o width: the optimize cache tile width in pixels.
2667 % o height: the optimize cache tile height in pixels.
2670 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2676 assert(image != (Image *) NULL);
2677 assert(image->signature == MagickSignature);
2678 if (image->debug != MagickFalse)
2679 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2680 cache_info=(CacheInfo *) image->cache;
2681 assert(cache_info->signature == MagickSignature);
2682 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2683 if (GetImagePixelCacheType(image) == DiskCache)
2684 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2693 + 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 %
2697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2699 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2700 % pixel cache. A virtual pixel is any pixel access that is outside the
2701 % boundaries of the image cache.
2703 % The format of the GetPixelCacheVirtualMethod() method is:
2705 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2707 % A description of each parameter follows:
2709 % o image: the image.
2712 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2717 assert(image != (Image *) NULL);
2718 assert(image->signature == MagickSignature);
2719 assert(image->cache != (Cache) NULL);
2720 cache_info=(CacheInfo *) image->cache;
2721 assert(cache_info->signature == MagickSignature);
2722 return(cache_info->virtual_pixel_method);
2726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2730 + 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 %
2734 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2736 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2737 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2739 % The format of the GetVirtualMetacontentFromCache() method is:
2741 % void *GetVirtualMetacontentFromCache(const Image *image)
2743 % A description of each parameter follows:
2745 % o image: the image.
2748 static const void *GetVirtualMetacontentFromCache(const Image *image)
2754 id = GetOpenMPThreadId();
2759 assert(image != (const Image *) NULL);
2760 assert(image->signature == MagickSignature);
2761 assert(image->cache != (Cache) NULL);
2762 cache_info=(CacheInfo *) image->cache;
2763 assert(cache_info->signature == MagickSignature);
2764 assert(id < (int) cache_info->number_threads);
2765 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2766 cache_info->nexus_info[id]);
2767 return(metacontent);
2771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2775 + 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 %
2779 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2781 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2784 % The format of the GetVirtualMetacontentFromNexus() method is:
2786 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2787 % NexusInfo *nexus_info)
2789 % A description of each parameter follows:
2791 % o cache: the pixel cache.
2793 % o nexus_info: the cache nexus to return the meta-content.
2796 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2797 NexusInfo *nexus_info)
2802 assert(cache != (Cache) NULL);
2803 cache_info=(CacheInfo *) cache;
2804 assert(cache_info->signature == MagickSignature);
2805 if (cache_info->storage_class == UndefinedClass)
2806 return((void *) NULL);
2807 return(nexus_info->metacontent);
2811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2815 % G e t V i r t u a l M e t a c o n t e n t %
2819 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2821 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2822 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2823 % returned if the meta-content are not available.
2825 % The format of the GetVirtualMetacontent() method is:
2827 % const void *GetVirtualMetacontent(const Image *image)
2829 % A description of each parameter follows:
2831 % o image: the image.
2834 MagickExport const void *GetVirtualMetacontent(const Image *image)
2840 id = GetOpenMPThreadId();
2845 assert(image != (const Image *) NULL);
2846 assert(image->signature == MagickSignature);
2847 assert(image->cache != (Cache) NULL);
2848 cache_info=(CacheInfo *) image->cache;
2849 assert(cache_info->signature == MagickSignature);
2850 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2851 if (metacontent != (void *) NULL)
2852 return(metacontent);
2853 assert(id < (int) cache_info->number_threads);
2854 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2855 cache_info->nexus_info[id]);
2856 return(metacontent);
2860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2864 + 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 %
2868 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2870 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2871 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2872 % is returned if the pixels are transferred, otherwise a NULL is returned.
2874 % The format of the GetVirtualPixelsFromNexus() method is:
2876 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2877 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2878 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2879 % ExceptionInfo *exception)
2881 % A description of each parameter follows:
2883 % o image: the image.
2885 % o virtual_pixel_method: the virtual pixel method.
2887 % o x,y,columns,rows: These values define the perimeter of a region of
2890 % o nexus_info: the cache nexus to acquire.
2892 % o exception: return any errors or warnings in this structure.
2899 0, 48, 12, 60, 3, 51, 15, 63,
2900 32, 16, 44, 28, 35, 19, 47, 31,
2901 8, 56, 4, 52, 11, 59, 7, 55,
2902 40, 24, 36, 20, 43, 27, 39, 23,
2903 2, 50, 14, 62, 1, 49, 13, 61,
2904 34, 18, 46, 30, 33, 17, 45, 29,
2905 10, 58, 6, 54, 9, 57, 5, 53,
2906 42, 26, 38, 22, 41, 25, 37, 21
2909 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2914 index=x+DitherMatrix[x & 0x07]-32L;
2917 if (index >= (ssize_t) columns)
2918 return((ssize_t) columns-1L);
2922 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2927 index=y+DitherMatrix[y & 0x07]-32L;
2930 if (index >= (ssize_t) rows)
2931 return((ssize_t) rows-1L);
2935 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2939 if (x >= (ssize_t) columns)
2940 return((ssize_t) (columns-1));
2944 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2948 if (y >= (ssize_t) rows)
2949 return((ssize_t) (rows-1));
2953 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2955 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2958 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2960 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2963 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2964 const size_t extent)
2970 Compute the remainder of dividing offset by extent. It returns not only
2971 the quotient (tile the offset falls in) but also the positive remainer
2972 within that tile such that 0 <= remainder < extent. This method is
2973 essentially a ldiv() using a floored modulo division rather than the
2974 normal default truncated modulo division.
2976 modulo.quotient=offset/(ssize_t) extent;
2979 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2983 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2984 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2985 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2986 ExceptionInfo *exception)
3003 virtual_pixel[CompositePixelChannel];
3008 register const Quantum
3021 register unsigned char
3028 *virtual_metacontent;
3033 assert(image != (const Image *) NULL);
3034 assert(image->signature == MagickSignature);
3035 assert(image->cache != (Cache) NULL);
3036 cache_info=(CacheInfo *) image->cache;
3037 assert(cache_info->signature == MagickSignature);
3038 if (cache_info->type == UndefinedCache)
3039 return((const Quantum *) NULL);
3042 region.width=columns;
3044 pixels=SetPixelCacheNexusPixels(image,ReadMode,®ion,nexus_info,exception);
3045 if (pixels == (Quantum *) NULL)
3046 return((const Quantum *) NULL);
3048 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3049 nexus_info->region.x;
3050 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3051 nexus_info->region.width-1L;
3052 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3053 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3054 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3055 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3061 Pixel request is inside cache extents.
3063 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3065 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3066 if (status == MagickFalse)
3067 return((const Quantum *) NULL);
3068 if (cache_info->metacontent_extent != 0)
3070 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3071 if (status == MagickFalse)
3072 return((const Quantum *) NULL);
3077 Pixel request is outside cache extents.
3079 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3080 virtual_nexus=AcquirePixelCacheNexus(1);
3081 if (virtual_nexus == (NexusInfo **) NULL)
3083 if (virtual_nexus != (NexusInfo **) NULL)
3084 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3085 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3086 "UnableToGetCacheNexus","'%s'",image->filename);
3087 return((const Quantum *) NULL);
3089 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3090 sizeof(*virtual_pixel));
3091 virtual_metacontent=(void *) NULL;
3092 switch (virtual_pixel_method)
3094 case BackgroundVirtualPixelMethod:
3095 case BlackVirtualPixelMethod:
3096 case GrayVirtualPixelMethod:
3097 case TransparentVirtualPixelMethod:
3098 case MaskVirtualPixelMethod:
3099 case WhiteVirtualPixelMethod:
3100 case EdgeVirtualPixelMethod:
3101 case CheckerTileVirtualPixelMethod:
3102 case HorizontalTileVirtualPixelMethod:
3103 case VerticalTileVirtualPixelMethod:
3105 if (cache_info->metacontent_extent != 0)
3108 Acquire a metacontent buffer.
3110 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3111 cache_info->metacontent_extent);
3112 if (virtual_metacontent == (void *) NULL)
3114 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3115 (void) ThrowMagickException(exception,GetMagickModule(),
3116 CacheError,"UnableToGetCacheNexus","'%s'",image->filename);
3117 return((const Quantum *) NULL);
3119 (void) ResetMagickMemory(virtual_metacontent,0,
3120 cache_info->metacontent_extent);
3122 switch (virtual_pixel_method)
3124 case BlackVirtualPixelMethod:
3126 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3127 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3128 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3131 case GrayVirtualPixelMethod:
3133 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3134 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3136 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3139 case TransparentVirtualPixelMethod:
3141 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3142 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3143 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3146 case MaskVirtualPixelMethod:
3147 case WhiteVirtualPixelMethod:
3149 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3150 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3151 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3156 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3158 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3160 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3162 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3164 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3174 for (v=0; v < (ssize_t) rows; v++)
3176 for (u=0; u < (ssize_t) columns; u+=length)
3178 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3179 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3180 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3188 Transfer a single pixel.
3190 length=(MagickSizeType) 1;
3191 switch (virtual_pixel_method)
3195 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3196 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3197 1UL,1UL,*virtual_nexus,exception);
3198 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3201 case RandomVirtualPixelMethod:
3203 if (cache_info->random_info == (RandomInfo *) NULL)
3204 cache_info->random_info=AcquireRandomInfo();
3205 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3206 RandomX(cache_info->random_info,cache_info->columns),
3207 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3208 *virtual_nexus,exception);
3209 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3212 case DitherVirtualPixelMethod:
3214 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3215 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3216 1UL,1UL,*virtual_nexus,exception);
3217 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3220 case TileVirtualPixelMethod:
3222 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3223 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3224 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3225 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3227 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3230 case MirrorVirtualPixelMethod:
3232 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3233 if ((x_modulo.quotient & 0x01) == 1L)
3234 x_modulo.remainder=(ssize_t) cache_info->columns-
3235 x_modulo.remainder-1L;
3236 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3237 if ((y_modulo.quotient & 0x01) == 1L)
3238 y_modulo.remainder=(ssize_t) cache_info->rows-
3239 y_modulo.remainder-1L;
3240 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3241 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3243 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3246 case HorizontalTileEdgeVirtualPixelMethod:
3248 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3249 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3250 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3251 *virtual_nexus,exception);
3252 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3255 case VerticalTileEdgeVirtualPixelMethod:
3257 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3258 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3259 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3260 *virtual_nexus,exception);
3261 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3264 case BackgroundVirtualPixelMethod:
3265 case BlackVirtualPixelMethod:
3266 case GrayVirtualPixelMethod:
3267 case TransparentVirtualPixelMethod:
3268 case MaskVirtualPixelMethod:
3269 case WhiteVirtualPixelMethod:
3272 r=virtual_metacontent;
3275 case EdgeVirtualPixelMethod:
3276 case CheckerTileVirtualPixelMethod:
3278 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3279 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3280 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3283 r=virtual_metacontent;
3286 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3287 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3289 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3292 case HorizontalTileVirtualPixelMethod:
3294 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3297 r=virtual_metacontent;
3300 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3301 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3302 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3303 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3305 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3308 case VerticalTileVirtualPixelMethod:
3310 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3313 r=virtual_metacontent;
3316 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3317 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3318 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3319 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3321 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3325 if (p == (const Quantum *) NULL)
3327 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3329 q+=cache_info->number_channels;
3330 if ((s != (void *) NULL) && (r != (const void *) NULL))
3332 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3333 s+=cache_info->metacontent_extent;
3338 Transfer a run of pixels.
3340 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3341 length,1UL,*virtual_nexus,exception);
3342 if (p == (const Quantum *) NULL)
3344 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3345 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3346 q+=length*cache_info->number_channels;
3347 if ((r != (void *) NULL) && (s != (const void *) NULL))
3349 (void) memcpy(s,r,(size_t) length);
3350 s+=length*cache_info->metacontent_extent;
3357 if (virtual_metacontent != (void *) NULL)
3358 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3359 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3368 + G e t V i r t u a l P i x e l C a c h e %
3372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3374 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3375 % cache as defined by the geometry parameters. A pointer to the pixels
3376 % is returned if the pixels are transferred, otherwise a NULL is returned.
3378 % The format of the GetVirtualPixelCache() method is:
3380 % const Quantum *GetVirtualPixelCache(const Image *image,
3381 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3382 % const ssize_t y,const size_t columns,const size_t rows,
3383 % ExceptionInfo *exception)
3385 % A description of each parameter follows:
3387 % o image: the image.
3389 % o virtual_pixel_method: the virtual pixel method.
3391 % o x,y,columns,rows: These values define the perimeter of a region of
3394 % o exception: return any errors or warnings in this structure.
3397 static const Quantum *GetVirtualPixelCache(const Image *image,
3398 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3399 const size_t columns,const size_t rows,ExceptionInfo *exception)
3405 id = GetOpenMPThreadId();
3410 assert(image != (const Image *) NULL);
3411 assert(image->signature == MagickSignature);
3412 assert(image->cache != (Cache) NULL);
3413 cache_info=(CacheInfo *) image->cache;
3414 assert(cache_info->signature == MagickSignature);
3415 assert(id < (int) cache_info->number_threads);
3416 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3417 cache_info->nexus_info[id],exception);
3422 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3426 % G e t V i r t u a l P i x e l Q u e u e %
3430 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3432 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3433 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3435 % The format of the GetVirtualPixelQueue() method is:
3437 % const Quantum *GetVirtualPixelQueue(const Image image)
3439 % A description of each parameter follows:
3441 % o image: the image.
3444 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3450 id = GetOpenMPThreadId();
3452 assert(image != (const Image *) NULL);
3453 assert(image->signature == MagickSignature);
3454 assert(image->cache != (Cache) NULL);
3455 cache_info=(CacheInfo *) image->cache;
3456 assert(cache_info->signature == MagickSignature);
3457 if (cache_info->methods.get_virtual_pixels_handler !=
3458 (GetVirtualPixelsHandler) NULL)
3459 return(cache_info->methods.get_virtual_pixels_handler(image));
3460 assert(id < (int) cache_info->number_threads);
3461 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3469 % G e t V i r t u a l P i x e l s %
3473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3475 % GetVirtualPixels() returns an immutable pixel region. If the
3476 % region is successfully accessed, a pointer to it is returned, otherwise
3477 % NULL is returned. The returned pointer may point to a temporary working
3478 % copy of the pixels or it may point to the original pixels in memory.
3479 % Performance is maximized if the selected region is part of one row, or one
3480 % or more full rows, since there is opportunity to access the pixels in-place
3481 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3482 % returned pointer must *never* be deallocated by the user.
3484 % Pixels accessed via the returned pointer represent a simple array of type
3485 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3486 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3487 % access the meta-content (of type void) corresponding to the the
3490 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3492 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3493 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3494 % GetCacheViewAuthenticPixels() instead.
3496 % The format of the GetVirtualPixels() method is:
3498 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3499 % const ssize_t y,const size_t columns,const size_t rows,
3500 % ExceptionInfo *exception)
3502 % A description of each parameter follows:
3504 % o image: the image.
3506 % o x,y,columns,rows: These values define the perimeter of a region of
3509 % o exception: return any errors or warnings in this structure.
3512 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3513 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3514 ExceptionInfo *exception)
3520 id = GetOpenMPThreadId();
3525 assert(image != (const Image *) NULL);
3526 assert(image->signature == MagickSignature);
3527 assert(image->cache != (Cache) NULL);
3528 cache_info=(CacheInfo *) image->cache;
3529 assert(cache_info->signature == MagickSignature);
3530 if (cache_info->methods.get_virtual_pixel_handler !=
3531 (GetVirtualPixelHandler) NULL)
3532 return(cache_info->methods.get_virtual_pixel_handler(image,
3533 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3534 assert(id < (int) cache_info->number_threads);
3535 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3536 columns,rows,cache_info->nexus_info[id],exception);
3541 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3545 + 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 %
3549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3551 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3552 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3554 % The format of the GetVirtualPixelsCache() method is:
3556 % Quantum *GetVirtualPixelsCache(const Image *image)
3558 % A description of each parameter follows:
3560 % o image: the image.
3563 static const Quantum *GetVirtualPixelsCache(const Image *image)
3569 id = GetOpenMPThreadId();
3571 assert(image != (const Image *) NULL);
3572 assert(image->signature == MagickSignature);
3573 assert(image->cache != (Cache) NULL);
3574 cache_info=(CacheInfo *) image->cache;
3575 assert(cache_info->signature == MagickSignature);
3576 assert(id < (int) cache_info->number_threads);
3577 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3585 + G e t V i r t u a l P i x e l s N e x u s %
3589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3591 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3594 % The format of the GetVirtualPixelsNexus() method is:
3596 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3597 % NexusInfo *nexus_info)
3599 % A description of each parameter follows:
3601 % o cache: the pixel cache.
3603 % o nexus_info: the cache nexus to return the colormap pixels.
3606 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3607 NexusInfo *nexus_info)
3612 assert(cache != (Cache) NULL);
3613 cache_info=(CacheInfo *) cache;
3614 assert(cache_info->signature == MagickSignature);
3615 if (cache_info->storage_class == UndefinedClass)
3616 return((Quantum *) NULL);
3617 return((const Quantum *) nexus_info->pixels);
3621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3625 + O p e n P i x e l C a c h e %
3629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3631 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3632 % dimensions, allocating space for the image pixels and optionally the
3633 % metacontent, and memory mapping the cache if it is disk based. The cache
3634 % nexus array is initialized as well.
3636 % The format of the OpenPixelCache() method is:
3638 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3639 % ExceptionInfo *exception)
3641 % A description of each parameter follows:
3643 % o image: the image.
3645 % o mode: ReadMode, WriteMode, or IOMode.
3647 % o exception: return any errors or warnings in this structure.
3651 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3653 cache_info->mapped=MagickFalse;
3654 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3655 (size_t) cache_info->length));
3656 if (cache_info->pixels == (Quantum *) NULL)
3658 cache_info->mapped=MagickTrue;
3659 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3660 cache_info->length);
3664 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3673 cache_info=(CacheInfo *) image->cache;
3674 if (image->debug != MagickFalse)
3677 format[MaxTextExtent],
3678 message[MaxTextExtent];
3680 (void) FormatMagickSize(length,MagickFalse,format);
3681 (void) FormatLocaleString(message,MaxTextExtent,
3682 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3683 cache_info->cache_filename,cache_info->file,format);
3684 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3686 if (length != (MagickSizeType) ((MagickOffsetType) length))
3687 return(MagickFalse);
3688 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3690 return(MagickFalse);
3691 if ((MagickSizeType) offset >= length)
3693 extent=(MagickOffsetType) length-1;
3694 #if !defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3699 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3700 if (count != (MagickOffsetType) 1)
3701 return(MagickFalse);
3708 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3710 return(MagickFalse);
3716 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3717 ExceptionInfo *exception)
3724 format[MaxTextExtent],
3725 message[MaxTextExtent];
3738 assert(image != (const Image *) NULL);
3739 assert(image->signature == MagickSignature);
3740 assert(image->cache != (Cache) NULL);
3741 if (image->debug != MagickFalse)
3742 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3743 if ((image->columns == 0) || (image->rows == 0))
3744 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3745 cache_info=(CacheInfo *) image->cache;
3746 assert(cache_info->signature == MagickSignature);
3747 source_info=(*cache_info);
3748 source_info.file=(-1);
3749 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3750 image->filename,(double) GetImageIndexInList(image));
3751 cache_info->storage_class=image->storage_class;
3752 cache_info->colorspace=image->colorspace;
3753 cache_info->alpha_trait=image->alpha_trait;
3754 cache_info->mask=image->mask;
3755 cache_info->rows=image->rows;
3756 cache_info->columns=image->columns;
3757 InitializePixelChannelMap(image);
3758 cache_info->number_channels=GetPixelChannels(image);
3759 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3760 sizeof(*image->channel_map));
3761 cache_info->metacontent_extent=image->metacontent_extent;
3762 cache_info->mode=mode;
3763 if (image->ping != MagickFalse)
3765 cache_info->type=PingCache;
3766 cache_info->pixels=(Quantum *) NULL;
3767 cache_info->metacontent=(void *) NULL;
3768 cache_info->length=0;
3771 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3772 packet_size=cache_info->number_channels*sizeof(Quantum);
3773 if (image->metacontent_extent != 0)
3774 packet_size+=cache_info->metacontent_extent;
3775 length=number_pixels*packet_size;
3776 columns=(size_t) (length/cache_info->rows/packet_size);
3777 if (cache_info->columns != columns)
3778 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3780 cache_info->length=length;
3781 status=AcquireMagickResource(AreaResource,cache_info->length);
3782 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3783 cache_info->metacontent_extent);
3784 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3786 status=AcquireMagickResource(MemoryResource,cache_info->length);
3787 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3788 (cache_info->type == MemoryCache))
3790 AllocatePixelCachePixels(cache_info);
3791 if (cache_info->pixels == (Quantum *) NULL)
3792 cache_info->pixels=source_info.pixels;
3796 Create memory pixel cache.
3799 if (image->debug != MagickFalse)
3801 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3802 (void) FormatLocaleString(message,MaxTextExtent,
3803 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3804 cache_info->filename,cache_info->mapped != MagickFalse ?
3805 "anonymous" : "heap",(double) cache_info->columns,(double)
3806 cache_info->rows,(double) cache_info->number_channels,
3808 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3811 cache_info->type=MemoryCache;
3812 cache_info->metacontent=(void *) NULL;
3813 if (cache_info->metacontent_extent != 0)
3814 cache_info->metacontent=(void *) (cache_info->pixels+
3815 number_pixels*cache_info->number_channels);
3816 if ((source_info.storage_class != UndefinedClass) &&
3819 status=ClonePixelCachePixels(cache_info,&source_info,
3821 RelinquishPixelCachePixels(&source_info);
3826 RelinquishMagickResource(MemoryResource,cache_info->length);
3829 Create pixel cache on disk.
3831 status=AcquireMagickResource(DiskResource,cache_info->length);
3832 if (status == MagickFalse)
3834 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3835 "CacheResourcesExhausted","'%s'",image->filename);
3836 return(MagickFalse);
3838 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3840 (void) ClosePixelCacheOnDisk(cache_info);
3841 *cache_info->cache_filename='\0';
3843 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3845 RelinquishMagickResource(DiskResource,cache_info->length);
3846 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3848 return(MagickFalse);
3850 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3851 cache_info->length);
3852 if (status == MagickFalse)
3854 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3856 return(MagickFalse);
3858 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3859 cache_info->metacontent_extent);
3860 if (length != (MagickSizeType) ((size_t) length))
3861 cache_info->type=DiskCache;
3864 status=AcquireMagickResource(MapResource,cache_info->length);
3865 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3866 (cache_info->type != MemoryCache))
3867 cache_info->type=DiskCache;
3870 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3871 cache_info->offset,(size_t) cache_info->length);
3872 if (cache_info->pixels == (Quantum *) NULL)
3874 cache_info->type=DiskCache;
3875 cache_info->pixels=source_info.pixels;
3880 Create file-backed memory-mapped pixel cache.
3883 (void) ClosePixelCacheOnDisk(cache_info);
3884 cache_info->type=MapCache;
3885 cache_info->mapped=MagickTrue;
3886 cache_info->metacontent=(void *) NULL;
3887 if (cache_info->metacontent_extent != 0)
3888 cache_info->metacontent=(void *) (cache_info->pixels+
3889 number_pixels*cache_info->number_channels);
3890 if ((source_info.storage_class != UndefinedClass) &&
3893 status=ClonePixelCachePixels(cache_info,&source_info,
3895 RelinquishPixelCachePixels(&source_info);
3897 if (image->debug != MagickFalse)
3899 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3900 (void) FormatLocaleString(message,MaxTextExtent,
3901 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
3902 cache_info->filename,cache_info->cache_filename,
3903 cache_info->file,(double) cache_info->columns,(double)
3904 cache_info->rows,(double) cache_info->number_channels,
3906 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3912 RelinquishMagickResource(MapResource,cache_info->length);
3915 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3917 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3918 RelinquishPixelCachePixels(&source_info);
3920 if (image->debug != MagickFalse)
3922 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3923 (void) FormatLocaleString(message,MaxTextExtent,
3924 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
3925 cache_info->cache_filename,cache_info->file,(double)
3926 cache_info->columns,(double) cache_info->rows,(double)
3927 cache_info->number_channels,format);
3928 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3938 + P e r s i s t P i x e l C a c h e %
3942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3944 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3945 % persistent pixel cache is one that resides on disk and is not destroyed
3946 % when the program exits.
3948 % The format of the PersistPixelCache() method is:
3950 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3951 % const MagickBooleanType attach,MagickOffsetType *offset,
3952 % ExceptionInfo *exception)
3954 % A description of each parameter follows:
3956 % o image: the image.
3958 % o filename: the persistent pixel cache filename.
3960 % o attach: A value other than zero initializes the persistent pixel cache.
3962 % o initialize: A value other than zero initializes the persistent pixel
3965 % o offset: the offset in the persistent cache to store pixels.
3967 % o exception: return any errors or warnings in this structure.
3970 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3971 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3972 ExceptionInfo *exception)
3987 assert(image != (Image *) NULL);
3988 assert(image->signature == MagickSignature);
3989 if (image->debug != MagickFalse)
3990 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3991 assert(image->cache != (void *) NULL);
3992 assert(filename != (const char *) NULL);
3993 assert(offset != (MagickOffsetType *) NULL);
3994 page_size=GetMagickPageSize();
3995 cache_info=(CacheInfo *) image->cache;
3996 assert(cache_info->signature == MagickSignature);
3997 if (attach != MagickFalse)
4000 Attach existing persistent pixel cache.
4002 if (image->debug != MagickFalse)
4003 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4004 "attach persistent cache");
4005 (void) CopyMagickString(cache_info->cache_filename,filename,
4007 cache_info->type=DiskCache;
4008 cache_info->offset=(*offset);
4009 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4010 return(MagickFalse);
4011 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4014 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4015 (cache_info->reference_count == 1))
4017 LockSemaphoreInfo(cache_info->semaphore);
4018 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4019 (cache_info->reference_count == 1))
4025 Usurp existing persistent pixel cache.
4027 status=rename_utf8(cache_info->cache_filename,filename);
4030 (void) CopyMagickString(cache_info->cache_filename,filename,
4032 *offset+=cache_info->length+page_size-(cache_info->length %
4034 UnlockSemaphoreInfo(cache_info->semaphore);
4035 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4036 if (image->debug != MagickFalse)
4037 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4038 "Usurp resident persistent cache");
4042 UnlockSemaphoreInfo(cache_info->semaphore);
4045 Clone persistent pixel cache.
4047 clone_image=(*image);
4048 clone_info=(CacheInfo *) clone_image.cache;
4049 image->cache=ClonePixelCache(cache_info);
4050 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4051 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4052 cache_info->type=DiskCache;
4053 cache_info->offset=(*offset);
4054 cache_info=(CacheInfo *) image->cache;
4055 status=OpenPixelCache(image,IOMode,exception);
4056 if (status != MagickFalse)
4057 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4058 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4059 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4068 + 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 %
4072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4074 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4075 % defined by the region rectangle and returns a pointer to the region. This
4076 % region is subsequently transferred from the pixel cache with
4077 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4078 % pixels are transferred, otherwise a NULL is returned.
4080 % The format of the QueueAuthenticPixelCacheNexus() method is:
4082 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4083 % const ssize_t y,const size_t columns,const size_t rows,
4084 % const MagickBooleanType clone,NexusInfo *nexus_info,
4085 % ExceptionInfo *exception)
4087 % A description of each parameter follows:
4089 % o image: the image.
4091 % o x,y,columns,rows: These values define the perimeter of a region of
4094 % o nexus_info: the cache nexus to set.
4096 % o clone: clone the pixel cache.
4098 % o exception: return any errors or warnings in this structure.
4101 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4102 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4103 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4118 Validate pixel cache geometry.
4120 assert(image != (const Image *) NULL);
4121 assert(image->signature == MagickSignature);
4122 assert(image->cache != (Cache) NULL);
4123 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4124 if (cache_info == (Cache) NULL)
4125 return((Quantum *) NULL);
4126 assert(cache_info->signature == MagickSignature);
4127 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4129 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4130 "NoPixelsDefinedInCache","'%s'",image->filename);
4131 return((Quantum *) NULL);
4133 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4134 (y >= (ssize_t) cache_info->rows))
4136 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4137 "PixelsAreNotAuthentic","'%s'",image->filename);
4138 return((Quantum *) NULL);
4140 offset=(MagickOffsetType) y*cache_info->columns+x;
4142 return((Quantum *) NULL);
4143 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4144 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4145 if ((MagickSizeType) offset >= number_pixels)
4146 return((Quantum *) NULL);
4152 region.width=columns;
4154 return(SetPixelCacheNexusPixels(image,WriteMode,®ion,nexus_info,exception));
4158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4162 + 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 %
4166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4168 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4169 % defined by the region rectangle and returns a pointer to the region. This
4170 % region is subsequently transferred from the pixel cache with
4171 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4172 % pixels are transferred, otherwise a NULL is returned.
4174 % The format of the QueueAuthenticPixelsCache() method is:
4176 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4177 % const ssize_t y,const size_t columns,const size_t rows,
4178 % ExceptionInfo *exception)
4180 % A description of each parameter follows:
4182 % o image: the image.
4184 % o x,y,columns,rows: These values define the perimeter of a region of
4187 % o exception: return any errors or warnings in this structure.
4190 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4191 const ssize_t y,const size_t columns,const size_t rows,
4192 ExceptionInfo *exception)
4198 id = GetOpenMPThreadId();
4203 assert(image != (const Image *) NULL);
4204 assert(image->signature == MagickSignature);
4205 assert(image->cache != (Cache) NULL);
4206 cache_info=(CacheInfo *) image->cache;
4207 assert(cache_info->signature == MagickSignature);
4208 assert(id < (int) cache_info->number_threads);
4209 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4210 cache_info->nexus_info[id],exception);
4215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4219 % Q u e u e A u t h e n t i c P i x e l s %
4223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4225 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4226 % successfully initialized a pointer to a Quantum array representing the
4227 % region is returned, otherwise NULL is returned. The returned pointer may
4228 % point to a temporary working buffer for the pixels or it may point to the
4229 % final location of the pixels in memory.
4231 % Write-only access means that any existing pixel values corresponding to
4232 % the region are ignored. This is useful if the initial image is being
4233 % created from scratch, or if the existing pixel values are to be
4234 % completely replaced without need to refer to their pre-existing values.
4235 % The application is free to read and write the pixel buffer returned by
4236 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4237 % initialize the pixel array values. Initializing pixel array values is the
4238 % application's responsibility.
4240 % Performance is maximized if the selected region is part of one row, or
4241 % one or more full rows, since then there is opportunity to access the
4242 % pixels in-place (without a copy) if the image is in memory, or in a
4243 % memory-mapped file. The returned pointer must *never* be deallocated
4246 % Pixels accessed via the returned pointer represent a simple array of type
4247 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4248 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4249 % obtain the meta-content (of type void) corresponding to the region.
4250 % Once the Quantum (and/or Quantum) array has been updated, the
4251 % changes must be saved back to the underlying image using
4252 % SyncAuthenticPixels() or they may be lost.
4254 % The format of the QueueAuthenticPixels() method is:
4256 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4257 % const ssize_t y,const size_t columns,const size_t rows,
4258 % ExceptionInfo *exception)
4260 % A description of each parameter follows:
4262 % o image: the image.
4264 % o x,y,columns,rows: These values define the perimeter of a region of
4267 % o exception: return any errors or warnings in this structure.
4270 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4271 const ssize_t y,const size_t columns,const size_t rows,
4272 ExceptionInfo *exception)
4278 id = GetOpenMPThreadId();
4283 assert(image != (Image *) NULL);
4284 assert(image->signature == MagickSignature);
4285 assert(image->cache != (Cache) NULL);
4286 cache_info=(CacheInfo *) image->cache;
4287 assert(cache_info->signature == MagickSignature);
4288 if (cache_info->methods.queue_authentic_pixels_handler !=
4289 (QueueAuthenticPixelsHandler) NULL)
4291 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4295 assert(id < (int) cache_info->number_threads);
4296 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4297 cache_info->nexus_info[id],exception);
4302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4306 + 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 %
4310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4312 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4315 % The format of the ReadPixelCacheMetacontent() method is:
4317 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4318 % NexusInfo *nexus_info,ExceptionInfo *exception)
4320 % A description of each parameter follows:
4322 % o cache_info: the pixel cache.
4324 % o nexus_info: the cache nexus to read the metacontent.
4326 % o exception: return any errors or warnings in this structure.
4329 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4330 NexusInfo *nexus_info,ExceptionInfo *exception)
4343 register unsigned char
4349 if (cache_info->metacontent_extent == 0)
4350 return(MagickFalse);
4351 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4353 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4354 nexus_info->region.x;
4355 length=(MagickSizeType) nexus_info->region.width*
4356 cache_info->metacontent_extent;
4357 rows=nexus_info->region.height;
4359 q=(unsigned char *) nexus_info->metacontent;
4360 switch (cache_info->type)
4365 register unsigned char
4369 Read meta-content from memory.
4371 if ((cache_info->columns == nexus_info->region.width) &&
4372 (extent == (MagickSizeType) ((size_t) extent)))
4377 p=(unsigned char *) cache_info->metacontent+offset*
4378 cache_info->metacontent_extent;
4379 for (y=0; y < (ssize_t) rows; y++)
4381 (void) memcpy(q,p,(size_t) length);
4382 p+=cache_info->metacontent_extent*cache_info->columns;
4383 q+=cache_info->metacontent_extent*nexus_info->region.width;
4390 Read meta content from disk.
4392 LockSemaphoreInfo(cache_info->file_semaphore);
4393 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4395 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4396 cache_info->cache_filename);
4397 UnlockSemaphoreInfo(cache_info->file_semaphore);
4398 return(MagickFalse);
4400 if ((cache_info->columns == nexus_info->region.width) &&
4401 (extent <= MagickMaxBufferExtent))
4406 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4407 for (y=0; y < (ssize_t) rows; y++)
4409 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4410 cache_info->number_channels*sizeof(Quantum)+offset*
4411 cache_info->metacontent_extent,length,(unsigned char *) q);
4412 if ((MagickSizeType) count != length)
4414 offset+=cache_info->columns;
4415 q+=cache_info->metacontent_extent*nexus_info->region.width;
4417 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4418 (void) ClosePixelCacheOnDisk(cache_info);
4419 UnlockSemaphoreInfo(cache_info->file_semaphore);
4420 if (y < (ssize_t) rows)
4422 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4423 cache_info->cache_filename);
4424 return(MagickFalse);
4431 if ((cache_info->debug != MagickFalse) &&
4432 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4433 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4434 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4435 nexus_info->region.width,(double) nexus_info->region.height,(double)
4436 nexus_info->region.x,(double) nexus_info->region.y);
4441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4445 + R e a d P i x e l C a c h e P i x e l s %
4449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4451 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4454 % The format of the ReadPixelCachePixels() method is:
4456 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4457 % NexusInfo *nexus_info,ExceptionInfo *exception)
4459 % A description of each parameter follows:
4461 % o cache_info: the pixel cache.
4463 % o nexus_info: the cache nexus to read the pixels.
4465 % o exception: return any errors or warnings in this structure.
4468 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4469 NexusInfo *nexus_info,ExceptionInfo *exception)
4488 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4490 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4491 nexus_info->region.x;
4492 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4494 rows=nexus_info->region.height;
4496 q=nexus_info->pixels;
4497 switch (cache_info->type)
4506 Read pixels from memory.
4508 if ((cache_info->columns == nexus_info->region.width) &&
4509 (extent == (MagickSizeType) ((size_t) extent)))
4514 p=cache_info->pixels+offset*cache_info->number_channels;
4515 for (y=0; y < (ssize_t) rows; y++)
4517 (void) memcpy(q,p,(size_t) length);
4518 p+=cache_info->number_channels*cache_info->columns;
4519 q+=cache_info->number_channels*nexus_info->region.width;
4526 Read pixels from disk.
4528 LockSemaphoreInfo(cache_info->file_semaphore);
4529 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4531 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4532 cache_info->cache_filename);
4533 UnlockSemaphoreInfo(cache_info->file_semaphore);
4534 return(MagickFalse);
4536 if ((cache_info->columns == nexus_info->region.width) &&
4537 (extent <= MagickMaxBufferExtent))
4542 for (y=0; y < (ssize_t) rows; y++)
4544 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4545 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4546 if ((MagickSizeType) count != length)
4548 offset+=cache_info->columns;
4549 q+=cache_info->number_channels*nexus_info->region.width;
4551 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4552 (void) ClosePixelCacheOnDisk(cache_info);
4553 UnlockSemaphoreInfo(cache_info->file_semaphore);
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 *) MagickAssumeAligned(AcquireAlignedMemory(1,
4743 (size_t) 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->alpha_trait=BlendPixelTrait;
4914 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4915 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4916 #pragma omp parallel for schedule(static,4) 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.alpha_trait == BlendPixelTrait) &&
4970 (image->alpha_trait != BlendPixelTrait))
4971 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4972 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4973 (IsGrayColorspace(image->colorspace) != MagickFalse))
4974 (void) TransformImageColorspace(image,RGBColorspace,exception);
4977 case TransparentVirtualPixelMethod:
4979 if (image->alpha_trait != BlendPixelTrait)
4980 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4994 + 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 %
4998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5000 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5001 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5002 % is synced, otherwise MagickFalse.
5004 % The format of the SyncAuthenticPixelCacheNexus() method is:
5006 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5007 % NexusInfo *nexus_info,ExceptionInfo *exception)
5009 % A description of each parameter follows:
5011 % o image: the image.
5013 % o nexus_info: the cache nexus to sync.
5015 % o exception: return any errors or warnings in this structure.
5018 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5019 NexusInfo *nexus_info,ExceptionInfo *exception)
5028 Transfer pixels to the cache.
5030 assert(image != (Image *) NULL);
5031 assert(image->signature == MagickSignature);
5032 if (image->cache == (Cache) NULL)
5033 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5034 cache_info=(CacheInfo *) image->cache;
5035 assert(cache_info->signature == MagickSignature);
5036 if (cache_info->type == UndefinedCache)
5037 return(MagickFalse);
5038 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5040 assert(cache_info->signature == MagickSignature);
5041 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5042 if ((cache_info->metacontent_extent != 0) &&
5043 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5044 return(MagickFalse);
5049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5053 + S y n c A u t h e n t i c P i x e l C a c h e %
5057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5059 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5060 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5061 % otherwise MagickFalse.
5063 % The format of the SyncAuthenticPixelsCache() method is:
5065 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5066 % ExceptionInfo *exception)
5068 % A description of each parameter follows:
5070 % o image: the image.
5072 % o exception: return any errors or warnings in this structure.
5075 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5076 ExceptionInfo *exception)
5082 id = GetOpenMPThreadId();
5087 assert(image != (Image *) NULL);
5088 assert(image->signature == MagickSignature);
5089 assert(image->cache != (Cache) NULL);
5090 cache_info=(CacheInfo *) image->cache;
5091 assert(cache_info->signature == MagickSignature);
5092 assert(id < (int) cache_info->number_threads);
5093 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5103 % S y n c A u t h e n t i c P i x e l s %
5107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5109 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5110 % The method returns MagickTrue if the pixel region is flushed, otherwise
5113 % The format of the SyncAuthenticPixels() method is:
5115 % MagickBooleanType SyncAuthenticPixels(Image *image,
5116 % ExceptionInfo *exception)
5118 % A description of each parameter follows:
5120 % o image: the image.
5122 % o exception: return any errors or warnings in this structure.
5125 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5126 ExceptionInfo *exception)
5132 id = GetOpenMPThreadId();
5137 assert(image != (Image *) NULL);
5138 assert(image->signature == MagickSignature);
5139 assert(image->cache != (Cache) NULL);
5140 cache_info=(CacheInfo *) image->cache;
5141 assert(cache_info->signature == MagickSignature);
5142 if (cache_info->methods.sync_authentic_pixels_handler !=
5143 (SyncAuthenticPixelsHandler) NULL)
5145 status=cache_info->methods.sync_authentic_pixels_handler(image,
5149 assert(id < (int) cache_info->number_threads);
5150 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5160 + S y n c I m a g e P i x e l C a c h e %
5164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5166 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5167 % The method returns MagickTrue if the pixel region is flushed, otherwise
5170 % The format of the SyncImagePixelCache() method is:
5172 % MagickBooleanType SyncImagePixelCache(Image *image,
5173 % ExceptionInfo *exception)
5175 % A description of each parameter follows:
5177 % o image: the image.
5179 % o exception: return any errors or warnings in this structure.
5182 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5183 ExceptionInfo *exception)
5188 assert(image != (Image *) NULL);
5189 assert(exception != (ExceptionInfo *) NULL);
5190 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5191 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5199 + 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 %
5203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5205 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5206 % of the pixel cache.
5208 % The format of the WritePixelCacheMetacontent() method is:
5210 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5211 % NexusInfo *nexus_info,ExceptionInfo *exception)
5213 % A description of each parameter follows:
5215 % o cache_info: the pixel cache.
5217 % o nexus_info: the cache nexus to write the meta-content.
5219 % o exception: return any errors or warnings in this structure.
5222 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5223 NexusInfo *nexus_info,ExceptionInfo *exception)
5233 register const unsigned char
5242 if (cache_info->metacontent_extent == 0)
5243 return(MagickFalse);
5244 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5246 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5247 nexus_info->region.x;
5248 length=(MagickSizeType) nexus_info->region.width*
5249 cache_info->metacontent_extent;
5250 rows=nexus_info->region.height;
5251 extent=(MagickSizeType) length*rows;
5252 p=(unsigned char *) nexus_info->metacontent;
5253 switch (cache_info->type)
5258 register unsigned char
5262 Write associated pixels to memory.
5264 if ((cache_info->columns == nexus_info->region.width) &&
5265 (extent == (MagickSizeType) ((size_t) extent)))
5270 q=(unsigned char *) cache_info->metacontent+offset*
5271 cache_info->metacontent_extent;
5272 for (y=0; y < (ssize_t) rows; y++)
5274 (void) memcpy(q,p,(size_t) length);
5275 p+=nexus_info->region.width*cache_info->metacontent_extent;
5276 q+=cache_info->columns*cache_info->metacontent_extent;
5283 Write associated pixels to disk.
5285 LockSemaphoreInfo(cache_info->file_semaphore);
5286 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5288 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5289 cache_info->cache_filename);
5290 UnlockSemaphoreInfo(cache_info->file_semaphore);
5291 return(MagickFalse);
5293 if ((cache_info->columns == nexus_info->region.width) &&
5294 (extent <= MagickMaxBufferExtent))
5299 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5300 for (y=0; y < (ssize_t) rows; y++)
5302 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5303 cache_info->number_channels*sizeof(Quantum)+offset*
5304 cache_info->metacontent_extent,length,(const unsigned char *) p);
5305 if ((MagickSizeType) count != length)
5307 p+=nexus_info->region.width*cache_info->metacontent_extent;
5308 offset+=cache_info->columns;
5310 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5311 (void) ClosePixelCacheOnDisk(cache_info);
5312 UnlockSemaphoreInfo(cache_info->file_semaphore);
5313 if (y < (ssize_t) rows)
5315 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5316 cache_info->cache_filename);
5317 return(MagickFalse);
5324 if ((cache_info->debug != MagickFalse) &&
5325 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5326 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5327 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5328 nexus_info->region.width,(double) nexus_info->region.height,(double)
5329 nexus_info->region.x,(double) nexus_info->region.y);
5334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5338 + W r i t e C a c h e P i x e l s %
5342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5344 % WritePixelCachePixels() writes image pixels to the specified region of the
5347 % The format of the WritePixelCachePixels() method is:
5349 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5350 % NexusInfo *nexus_info,ExceptionInfo *exception)
5352 % A description of each parameter follows:
5354 % o cache_info: the pixel cache.
5356 % o nexus_info: the cache nexus to write the pixels.
5358 % o exception: return any errors or warnings in this structure.
5361 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5362 NexusInfo *nexus_info,ExceptionInfo *exception)
5372 register const Quantum
5381 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5383 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5384 nexus_info->region.x;
5385 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5387 rows=nexus_info->region.height;
5389 p=nexus_info->pixels;
5390 switch (cache_info->type)
5399 Write pixels to memory.
5401 if ((cache_info->columns == nexus_info->region.width) &&
5402 (extent == (MagickSizeType) ((size_t) extent)))
5407 q=cache_info->pixels+offset*cache_info->number_channels;
5408 for (y=0; y < (ssize_t) rows; y++)
5410 (void) memcpy(q,p,(size_t) length);
5411 p+=nexus_info->region.width*cache_info->number_channels;
5412 q+=cache_info->columns*cache_info->number_channels;
5419 Write pixels to disk.
5421 LockSemaphoreInfo(cache_info->file_semaphore);
5422 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5424 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5425 cache_info->cache_filename);
5426 UnlockSemaphoreInfo(cache_info->file_semaphore);
5427 return(MagickFalse);
5429 if ((cache_info->columns == nexus_info->region.width) &&
5430 (extent <= MagickMaxBufferExtent))
5435 for (y=0; y < (ssize_t) rows; y++)
5437 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5438 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5440 if ((MagickSizeType) count != length)
5442 p+=nexus_info->region.width*cache_info->number_channels;
5443 offset+=cache_info->columns;
5445 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5446 (void) ClosePixelCacheOnDisk(cache_info);
5447 UnlockSemaphoreInfo(cache_info->file_semaphore);
5448 if (y < (ssize_t) rows)
5450 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5451 cache_info->cache_filename);
5452 return(MagickFalse);
5459 if ((cache_info->debug != MagickFalse) &&
5460 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5461 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5462 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5463 nexus_info->region.width,(double) nexus_info->region.height,(double)
5464 nexus_info->region.x,(double) nexus_info->region.y);