2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/composite-private.h"
50 #include "MagickCore/exception.h"
51 #include "MagickCore/exception-private.h"
52 #include "MagickCore/geometry.h"
53 #include "MagickCore/list.h"
54 #include "MagickCore/log.h"
55 #include "MagickCore/magick.h"
56 #include "MagickCore/memory_.h"
57 #include "MagickCore/nt-base-private.h"
58 #include "MagickCore/pixel.h"
59 #include "MagickCore/pixel-accessor.h"
60 #include "MagickCore/policy.h"
61 #include "MagickCore/quantum.h"
62 #include "MagickCore/random_.h"
63 #include "MagickCore/resource_.h"
64 #include "MagickCore/semaphore.h"
65 #include "MagickCore/splay-tree.h"
66 #include "MagickCore/string_.h"
67 #include "MagickCore/string-private.h"
68 #include "MagickCore/thread-private.h"
69 #include "MagickCore/utility.h"
70 #include "MagickCore/utility-private.h"
71 #if defined(MAGICKCORE_ZLIB_DELEGATE)
78 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
79 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
80 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
85 typedef struct _MagickModulo
115 Forward declarations.
117 #if defined(__cplusplus) || defined(c_plusplus)
122 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
126 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
127 const ssize_t,const size_t,const size_t,ExceptionInfo *),
128 *GetVirtualPixelsCache(const Image *);
131 *GetVirtualMetacontentFromCache(const Image *);
133 static MagickBooleanType
134 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
135 Quantum *,ExceptionInfo *),
136 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
137 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
138 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
139 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
140 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
141 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
142 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
143 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
146 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
147 const size_t,ExceptionInfo *),
148 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
149 const size_t,ExceptionInfo *),
150 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
151 ExceptionInfo *) magick_hot_spot;
153 #if defined(__cplusplus) || defined(c_plusplus)
160 static volatile MagickBooleanType
161 instantiate_cache = MagickFalse;
164 *cache_semaphore = (SemaphoreInfo *) NULL;
167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171 + A c q u i r e P i x e l C a c h e %
175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177 % AcquirePixelCache() acquires a pixel cache.
179 % The format of the AcquirePixelCache() method is:
181 % Cache AcquirePixelCache(const size_t number_threads)
183 % A description of each parameter follows:
185 % o number_threads: the number of nexus threads.
188 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
193 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
194 if (cache_info == (CacheInfo *) NULL)
195 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
196 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
197 cache_info->type=UndefinedCache;
198 cache_info->mode=IOMode;
199 cache_info->colorspace=RGBColorspace;
200 cache_info->file=(-1);
201 cache_info->id=GetMagickThreadId();
202 cache_info->number_threads=number_threads;
203 if (number_threads == 0)
204 cache_info->number_threads=GetOpenMPMaximumThreads();
205 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
206 if (cache_info->nexus_info == (NexusInfo **) NULL)
207 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
208 cache_info->semaphore=AllocateSemaphoreInfo();
209 cache_info->reference_count=1;
210 cache_info->disk_semaphore=AllocateSemaphoreInfo();
211 cache_info->debug=IsEventLogging();
212 cache_info->signature=MagickSignature;
213 return((Cache ) cache_info);
217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
221 % A c q u i r e P i x e l C a c h e N e x u s %
225 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
229 % The format of the AcquirePixelCacheNexus method is:
231 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
233 % A description of each parameter follows:
235 % o number_threads: the number of nexus threads.
238 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
246 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
247 sizeof(*nexus_info));
248 if (nexus_info == (NexusInfo **) NULL)
249 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
250 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
251 sizeof(**nexus_info));
252 if (nexus_info[0] == (NexusInfo *) NULL)
253 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
254 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
255 for (i=0; i < (ssize_t) number_threads; i++)
257 nexus_info[i]=(&nexus_info[0][i]);
258 nexus_info[i]->signature=MagickSignature;
264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
268 + A c q u i r e P i x e l C a c h e P i x e l s %
272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 % AcquirePixelCachePixels() returns the pixels associated with the specified
277 % The format of the AcquirePixelCachePixels() method is:
279 % const void *AcquirePixelCachePixels(const Image *image,
280 % MagickSizeType *length,ExceptionInfo *exception)
282 % A description of each parameter follows:
284 % o image: the image.
286 % o length: the pixel cache length.
288 % o exception: return any errors or warnings in this structure.
291 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
292 MagickSizeType *length,ExceptionInfo *exception)
297 assert(image != (const Image *) NULL);
298 assert(image->signature == MagickSignature);
299 assert(exception != (ExceptionInfo *) NULL);
300 assert(exception->signature == MagickSignature);
301 assert(image->cache != (Cache) NULL);
302 cache_info=(CacheInfo *) image->cache;
303 assert(cache_info->signature == MagickSignature);
305 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
306 return((const void *) NULL);
307 *length=cache_info->length;
308 return((const void *) cache_info->pixels);
312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
316 + C a c h e C o m p o n e n t G e n e s i s %
320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322 % CacheComponentGenesis() instantiates the cache component.
324 % The format of the CacheComponentGenesis method is:
326 % MagickBooleanType CacheComponentGenesis(void)
329 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
331 AcquireSemaphoreInfo(&cache_semaphore);
336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 + C a c h e C o m p o n e n t T e r m i n u s %
344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 % CacheComponentTerminus() destroys the cache component.
348 % The format of the CacheComponentTerminus() method is:
350 % CacheComponentTerminus(void)
353 MagickPrivate void CacheComponentTerminus(void)
355 if (cache_semaphore == (SemaphoreInfo *) NULL)
356 AcquireSemaphoreInfo(&cache_semaphore);
357 LockSemaphoreInfo(cache_semaphore);
358 instantiate_cache=MagickFalse;
359 UnlockSemaphoreInfo(cache_semaphore);
360 DestroySemaphoreInfo(&cache_semaphore);
364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
368 + C l o n e P i x e l C a c h e %
372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 % ClonePixelCache() clones a pixel cache.
376 % The format of the ClonePixelCache() method is:
378 % Cache ClonePixelCache(const Cache cache)
380 % A description of each parameter follows:
382 % o cache: the pixel cache.
385 MagickPrivate Cache ClonePixelCache(const Cache cache)
393 assert(cache != NULL);
394 cache_info=(const CacheInfo *) cache;
395 assert(cache_info->signature == MagickSignature);
396 if (cache_info->debug != MagickFalse)
397 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
398 cache_info->filename);
399 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
400 if (clone_info == (Cache) NULL)
401 return((Cache) NULL);
402 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
403 return((Cache ) clone_info);
407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411 + C l o n e P i x e l C a c h e P i x e l s %
415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
416 % ClonePixelCachePixels() clones the source pixel cache to the destination
419 % The format of the ClonePixelCachePixels() method is:
421 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
422 % CacheInfo *source_info,ExceptionInfo *exception)
424 % A description of each parameter follows:
426 % o cache_info: the pixel cache.
428 % o source_info: the source pixel cache.
430 % o exception: return any errors or warnings in this structure.
434 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
440 LockSemaphoreInfo(cache_info->disk_semaphore);
441 if (cache_info->file != -1)
443 status=close(cache_info->file);
444 cache_info->file=(-1);
445 RelinquishMagickResource(FileResource,1);
447 UnlockSemaphoreInfo(cache_info->disk_semaphore);
448 return(status == -1 ? MagickFalse : MagickTrue);
451 static inline MagickSizeType MagickMax(const MagickSizeType x,
452 const MagickSizeType y)
459 static inline MagickSizeType MagickMin(const MagickSizeType x,
460 const MagickSizeType y)
467 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
474 Open pixel cache on disk.
476 LockSemaphoreInfo(cache_info->disk_semaphore);
477 if (cache_info->file != -1)
479 UnlockSemaphoreInfo(cache_info->disk_semaphore);
480 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 UnlockSemaphoreInfo(cache_info->disk_semaphore);
515 (void) AcquireMagickResource(FileResource,1);
516 cache_info->file=file;
517 cache_info->mode=mode;
518 cache_info->timestamp=time(0);
519 UnlockSemaphoreInfo(cache_info->disk_semaphore);
523 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
524 const MagickOffsetType offset,const MagickSizeType length,
525 unsigned char *restrict buffer)
527 register MagickOffsetType
533 cache_info->timestamp=time(0);
534 #if !defined(MAGICKCORE_HAVE_PREAD)
535 LockSemaphoreInfo(cache_info->disk_semaphore);
536 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
538 UnlockSemaphoreInfo(cache_info->disk_semaphore);
539 return((MagickOffsetType) -1);
543 for (i=0; i < (MagickOffsetType) length; i+=count)
545 #if !defined(MAGICKCORE_HAVE_PREAD)
546 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
547 (MagickSizeType) SSIZE_MAX));
549 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
550 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
561 #if !defined(MAGICKCORE_HAVE_PREAD)
562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
567 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
568 const MagickOffsetType offset,const MagickSizeType length,
569 const unsigned char *restrict buffer)
571 register MagickOffsetType
577 cache_info->timestamp=time(0);
578 #if !defined(MAGICKCORE_HAVE_PWRITE)
579 LockSemaphoreInfo(cache_info->disk_semaphore);
580 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
582 UnlockSemaphoreInfo(cache_info->disk_semaphore);
583 return((MagickOffsetType) -1);
587 for (i=0; i < (MagickOffsetType) length; i+=count)
589 #if !defined(MAGICKCORE_HAVE_PWRITE)
590 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
591 (MagickSizeType) SSIZE_MAX));
593 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
594 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
605 #if !defined(MAGICKCORE_HAVE_PWRITE)
606 UnlockSemaphoreInfo(cache_info->disk_semaphore);
611 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
612 CacheInfo *cache_info,ExceptionInfo *exception)
617 register MagickOffsetType
627 Clone pixel cache (both caches on disk).
629 if (cache_info->debug != MagickFalse)
630 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
631 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
633 if (blob == (unsigned char *) NULL)
635 (void) ThrowMagickException(exception,GetMagickModule(),
636 ResourceLimitError,"MemoryAllocationFailed","`%s'",
637 cache_info->filename);
640 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
642 blob=(unsigned char *) RelinquishMagickMemory(blob);
643 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
644 cache_info->cache_filename);
647 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
649 (void) ClosePixelCacheOnDisk(cache_info);
650 blob=(unsigned char *) RelinquishMagickMemory(blob);
651 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
652 clone_info->cache_filename);
656 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
658 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
659 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
663 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
664 cache_info->cache_filename);
667 length=(size_t) count;
668 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
669 if ((MagickSizeType) count != length)
671 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
672 clone_info->cache_filename);
676 (void) ClosePixelCacheOnDisk(clone_info);
677 (void) ClosePixelCacheOnDisk(cache_info);
678 blob=(unsigned char *) RelinquishMagickMemory(blob);
679 if (i < (MagickOffsetType) cache_info->length)
684 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
685 CacheInfo *cache_info,ExceptionInfo *exception)
690 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
693 Clone pixel cache (both caches in memory).
695 if (cache_info->debug != MagickFalse)
696 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
697 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
701 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
704 Clone pixel cache (one cache on disk, one in memory).
706 if (cache_info->debug != MagickFalse)
707 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
708 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
710 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
711 cache_info->cache_filename);
714 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
715 cache_info->length,(unsigned char *) clone_info->pixels);
716 (void) ClosePixelCacheOnDisk(cache_info);
717 if ((MagickSizeType) count != cache_info->length)
719 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
720 cache_info->cache_filename);
725 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
728 Clone pixel cache (one cache on disk, one in memory).
730 if (clone_info->debug != MagickFalse)
731 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
732 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
734 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
735 clone_info->cache_filename);
738 count=WritePixelCacheRegion(clone_info,clone_info->offset,
739 clone_info->length,(unsigned char *) cache_info->pixels);
740 (void) ClosePixelCacheOnDisk(clone_info);
741 if ((MagickSizeType) count != clone_info->length)
743 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
744 clone_info->cache_filename);
750 Clone pixel cache (both caches on disk).
752 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
755 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
756 CacheInfo *cache_info,ExceptionInfo *exception)
769 register unsigned char
782 Clone pixel cache (unoptimized).
784 if (cache_info->debug != MagickFalse)
786 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
787 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
789 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
790 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
792 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
793 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
795 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
797 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
798 clone_info->number_channels)*sizeof(Quantum),MagickMax(
799 cache_info->metacontent_extent,clone_info->metacontent_extent));
800 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
801 if (blob == (unsigned char *) NULL)
803 (void) ThrowMagickException(exception,GetMagickModule(),
804 ResourceLimitError,"MemoryAllocationFailed","`%s'",
805 cache_info->filename);
808 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
811 if (cache_info->type == DiskCache)
813 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
815 blob=(unsigned char *) RelinquishMagickMemory(blob);
816 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
817 cache_info->cache_filename);
820 cache_offset=cache_info->offset;
822 if (clone_info->type == DiskCache)
824 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
826 blob=(unsigned char *) RelinquishMagickMemory(blob);
827 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
828 clone_info->cache_filename);
831 clone_offset=clone_info->offset;
834 Clone pixel channels.
838 for (y=0; y < (ssize_t) cache_info->rows; y++)
840 for (x=0; x < (ssize_t) cache_info->columns; x++)
846 Read a set of pixel channels.
848 length=cache_info->number_channels*sizeof(Quantum);
849 if (cache_info->type != DiskCache)
850 p=(unsigned char *) cache_info->pixels+cache_offset;
853 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
854 if ((MagickSizeType) count != length)
860 cache_offset+=length;
861 if ((y < (ssize_t) clone_info->rows) &&
862 (x < (ssize_t) clone_info->columns))
863 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
875 Write a set of pixel channels.
877 channel=clone_info->channel_map[i].channel;
878 traits=cache_info->channel_map[channel].traits;
879 if (traits == UndefinedPixelTrait)
881 clone_offset+=sizeof(Quantum);
884 offset=cache_info->channel_map[channel].offset;
885 if (clone_info->type != DiskCache)
886 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
887 offset*sizeof(Quantum),sizeof(Quantum));
890 count=WritePixelCacheRegion(clone_info,clone_offset,
891 sizeof(Quantum),p+offset*sizeof(Quantum));
892 if ((MagickSizeType) count != sizeof(Quantum))
898 clone_offset+=sizeof(Quantum);
901 length=clone_info->number_channels*sizeof(Quantum);
902 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
903 for ( ; x < (ssize_t) clone_info->columns; x++)
906 Set remaining columns as undefined.
908 if (clone_info->type != DiskCache)
909 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
913 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
914 if ((MagickSizeType) count != length)
920 clone_offset+=length;
923 length=clone_info->number_channels*sizeof(Quantum);
924 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
925 for ( ; y < (ssize_t) clone_info->rows; y++)
928 Set remaining rows as undefined.
930 for (x=0; x < (ssize_t) clone_info->columns; x++)
932 if (clone_info->type != DiskCache)
933 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
937 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
938 if ((MagickSizeType) count != length)
944 clone_offset+=length;
947 if ((cache_info->metacontent_extent != 0) ||
948 (clone_info->metacontent_extent != 0))
953 for (y=0; y < (ssize_t) cache_info->rows; y++)
955 for (x=0; x < (ssize_t) cache_info->columns; x++)
958 Read a set of metacontent.
960 length=cache_info->metacontent_extent;
961 if (cache_info->type != DiskCache)
962 p=(unsigned char *) cache_info->pixels+cache_offset;
965 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
966 if ((MagickSizeType) count != length)
972 cache_offset+=length;
973 if ((y < (ssize_t) clone_info->rows) &&
974 (x < (ssize_t) clone_info->columns))
977 Write a set of metacontent.
979 length=clone_info->metacontent_extent;
980 if (clone_info->type != DiskCache)
981 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
985 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
986 if ((MagickSizeType) count != length)
992 clone_offset+=length;
995 length=clone_info->metacontent_extent;
996 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
997 for ( ; x < (ssize_t) clone_info->columns; x++)
1000 Set remaining columns as undefined.
1002 if (clone_info->type != DiskCache)
1003 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1007 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1008 if ((MagickSizeType) count != length)
1014 clone_offset+=length;
1017 length=clone_info->metacontent_extent;
1018 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1019 for ( ; y < (ssize_t) clone_info->rows; y++)
1022 Set remaining rows as undefined.
1024 for (x=0; x < (ssize_t) clone_info->columns; x++)
1026 if (clone_info->type != DiskCache)
1027 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1031 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1032 if ((MagickSizeType) count != length)
1038 clone_offset+=length;
1042 if (clone_info->type == DiskCache)
1043 (void) ClosePixelCacheOnDisk(clone_info);
1044 if (cache_info->type == DiskCache)
1045 (void) ClosePixelCacheOnDisk(cache_info);
1046 blob=(unsigned char *) RelinquishMagickMemory(blob);
1050 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1051 CacheInfo *cache_info,ExceptionInfo *exception)
1057 if (cache_info->type == PingCache)
1059 p=cache_info->channel_map;
1060 q=clone_info->channel_map;
1061 if ((cache_info->columns == clone_info->columns) &&
1062 (cache_info->rows == clone_info->rows) &&
1063 (cache_info->number_channels == clone_info->number_channels) &&
1064 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1065 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1066 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1067 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1075 + C l o n e P i x e l C a c h e M e t h o d s %
1079 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1084 % The format of the ClonePixelCacheMethods() method is:
1086 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1088 % A description of each parameter follows:
1090 % o clone: Specifies a pointer to a Cache structure.
1092 % o cache: the pixel cache.
1095 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1101 assert(clone != (Cache) NULL);
1102 source_info=(CacheInfo *) clone;
1103 assert(source_info->signature == MagickSignature);
1104 if (source_info->debug != MagickFalse)
1105 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1106 source_info->filename);
1107 assert(cache != (Cache) NULL);
1108 cache_info=(CacheInfo *) cache;
1109 assert(cache_info->signature == MagickSignature);
1110 source_info->methods=cache_info->methods;
1114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1118 + D e s t r o y I m a g e P i x e l C a c h e %
1122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1124 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1126 % The format of the DestroyImagePixelCache() method is:
1128 % void DestroyImagePixelCache(Image *image)
1130 % A description of each parameter follows:
1132 % o image: the image.
1135 static void DestroyImagePixelCache(Image *image)
1137 assert(image != (Image *) NULL);
1138 assert(image->signature == MagickSignature);
1139 if (image->debug != MagickFalse)
1140 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1141 if (image->cache == (void *) NULL)
1143 image->cache=DestroyPixelCache(image->cache);
1147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1151 + D e s t r o y I m a g e P i x e l s %
1155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1157 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1159 % The format of the DestroyImagePixels() method is:
1161 % void DestroyImagePixels(Image *image)
1163 % A description of each parameter follows:
1165 % o image: the image.
1168 MagickExport void DestroyImagePixels(Image *image)
1173 assert(image != (const Image *) NULL);
1174 assert(image->signature == MagickSignature);
1175 if (image->debug != MagickFalse)
1176 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1177 assert(image->cache != (Cache) NULL);
1178 cache_info=(CacheInfo *) image->cache;
1179 assert(cache_info->signature == MagickSignature);
1180 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1182 cache_info->methods.destroy_pixel_handler(image);
1185 image->cache=DestroyPixelCache(image->cache);
1189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1193 + D e s t r o y P i x e l C a c h e %
1197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1201 % The format of the DestroyPixelCache() method is:
1203 % Cache DestroyPixelCache(Cache cache)
1205 % A description of each parameter follows:
1207 % o cache: the pixel cache.
1211 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1213 switch (cache_info->type)
1217 if (cache_info->mapped == MagickFalse)
1218 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
1219 cache_info->pixels);
1221 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1222 (size_t) cache_info->length);
1223 RelinquishMagickResource(MemoryResource,cache_info->length);
1228 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1229 cache_info->length);
1230 RelinquishMagickResource(MapResource,cache_info->length);
1234 if (cache_info->file != -1)
1235 (void) ClosePixelCacheOnDisk(cache_info);
1236 RelinquishMagickResource(DiskResource,cache_info->length);
1242 cache_info->type=UndefinedCache;
1243 cache_info->mapped=MagickFalse;
1244 cache_info->metacontent=(void *) NULL;
1247 MagickPrivate Cache DestroyPixelCache(Cache cache)
1252 assert(cache != (Cache) NULL);
1253 cache_info=(CacheInfo *) cache;
1254 assert(cache_info->signature == MagickSignature);
1255 if (cache_info->debug != MagickFalse)
1256 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1257 cache_info->filename);
1258 LockSemaphoreInfo(cache_info->semaphore);
1259 cache_info->reference_count--;
1260 if (cache_info->reference_count != 0)
1262 UnlockSemaphoreInfo(cache_info->semaphore);
1263 return((Cache) NULL);
1265 UnlockSemaphoreInfo(cache_info->semaphore);
1266 if (cache_info->debug != MagickFalse)
1269 message[MaxTextExtent];
1271 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1272 cache_info->filename);
1273 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1275 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1276 (cache_info->type != DiskCache)))
1277 RelinquishPixelCachePixels(cache_info);
1280 RelinquishPixelCachePixels(cache_info);
1281 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1283 *cache_info->cache_filename='\0';
1284 if (cache_info->nexus_info != (NexusInfo **) NULL)
1285 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1286 cache_info->number_threads);
1287 if (cache_info->random_info != (RandomInfo *) NULL)
1288 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1289 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1290 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1291 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1292 DestroySemaphoreInfo(&cache_info->semaphore);
1293 cache_info->signature=(~MagickSignature);
1294 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304 + D e s t r o y P i x e l C a c h e N e x u s %
1308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1310 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1312 % The format of the DestroyPixelCacheNexus() method is:
1314 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1315 % const size_t number_threads)
1317 % A description of each parameter follows:
1319 % o nexus_info: the nexus to destroy.
1321 % o number_threads: the number of nexus threads.
1325 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1327 if (nexus_info->mapped == MagickFalse)
1328 (void) RelinquishAlignedMemory(nexus_info->cache);
1330 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1331 nexus_info->cache=(Quantum *) NULL;
1332 nexus_info->pixels=(Quantum *) NULL;
1333 nexus_info->metacontent=(void *) NULL;
1334 nexus_info->length=0;
1335 nexus_info->mapped=MagickFalse;
1338 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1339 const size_t number_threads)
1344 assert(nexus_info != (NexusInfo **) NULL);
1345 for (i=0; i < (ssize_t) number_threads; i++)
1347 if (nexus_info[i]->cache != (Quantum *) NULL)
1348 RelinquishCacheNexusPixels(nexus_info[i]);
1349 nexus_info[i]->signature=(~MagickSignature);
1351 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1352 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1361 % G e t A u t h e n t i c M e t a c o n t e n t %
1365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1367 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1368 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1369 % returned if the associated pixels are not available.
1371 % The format of the GetAuthenticMetacontent() method is:
1373 % void *GetAuthenticMetacontent(const Image *image)
1375 % A description of each parameter follows:
1377 % o image: the image.
1380 MagickExport void *GetAuthenticMetacontent(const Image *image)
1386 id = GetOpenMPThreadId();
1391 assert(image != (const Image *) NULL);
1392 assert(image->signature == MagickSignature);
1393 assert(image->cache != (Cache) NULL);
1394 cache_info=(CacheInfo *) image->cache;
1395 assert(cache_info->signature == MagickSignature);
1396 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1397 (GetAuthenticMetacontentFromHandler) NULL)
1399 metacontent=cache_info->methods.
1400 get_authentic_metacontent_from_handler(image);
1401 return(metacontent);
1403 assert(id < (int) cache_info->number_threads);
1404 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1405 cache_info->nexus_info[id]);
1406 return(metacontent);
1410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414 + 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 %
1418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1421 % with the last call to QueueAuthenticPixelsCache() or
1422 % GetAuthenticPixelsCache().
1424 % The format of the GetAuthenticMetacontentFromCache() method is:
1426 % void *GetAuthenticMetacontentFromCache(const Image *image)
1428 % A description of each parameter follows:
1430 % o image: the image.
1433 static void *GetAuthenticMetacontentFromCache(const Image *image)
1439 id = GetOpenMPThreadId();
1444 assert(image != (const Image *) NULL);
1445 assert(image->signature == MagickSignature);
1446 assert(image->cache != (Cache) NULL);
1447 cache_info=(CacheInfo *) image->cache;
1448 assert(cache_info->signature == MagickSignature);
1449 assert(id < (int) cache_info->number_threads);
1450 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1451 cache_info->nexus_info[id]);
1452 return(metacontent);
1456 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1460 + 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 %
1464 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1466 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1467 % disk pixel cache as defined by the geometry parameters. A pointer to the
1468 % pixels is returned if the pixels are transferred, otherwise a NULL is
1471 % The format of the GetAuthenticPixelCacheNexus() method is:
1473 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1474 % const ssize_t y,const size_t columns,const size_t rows,
1475 % NexusInfo *nexus_info,ExceptionInfo *exception)
1477 % A description of each parameter follows:
1479 % o image: the image.
1481 % o x,y,columns,rows: These values define the perimeter of a region of
1484 % o nexus_info: the cache nexus to return.
1486 % o exception: return any errors or warnings in this structure.
1490 static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
1491 NexusInfo *nexus_info)
1499 if (cache_info->type == PingCache)
1501 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1502 nexus_info->region.x;
1503 status=nexus_info->pixels == (cache_info->pixels+offset*
1504 cache_info->number_channels) ? MagickTrue : MagickFalse;
1508 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1509 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1510 NexusInfo *nexus_info,ExceptionInfo *exception)
1519 Transfer pixels from the cache.
1521 assert(image != (Image *) NULL);
1522 assert(image->signature == MagickSignature);
1523 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1525 if (q == (Quantum *) NULL)
1526 return((Quantum *) NULL);
1527 cache_info=(CacheInfo *) image->cache;
1528 assert(cache_info->signature == MagickSignature);
1529 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1531 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1532 return((Quantum *) NULL);
1533 if (cache_info->metacontent_extent != 0)
1534 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1535 return((Quantum *) NULL);
1540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1544 + 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 %
1548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1550 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1551 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1553 % The format of the GetAuthenticPixelsFromCache() method is:
1555 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1557 % A description of each parameter follows:
1559 % o image: the image.
1562 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1568 id = GetOpenMPThreadId();
1570 assert(image != (const Image *) NULL);
1571 assert(image->signature == MagickSignature);
1572 assert(image->cache != (Cache) NULL);
1573 cache_info=(CacheInfo *) image->cache;
1574 assert(cache_info->signature == MagickSignature);
1575 assert(id < (int) cache_info->number_threads);
1576 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1584 % G e t A u t h e n t i c P i x e l Q u e u e %
1588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590 % GetAuthenticPixelQueue() returns the authentic pixels associated
1591 % corresponding with the last call to QueueAuthenticPixels() or
1592 % GetAuthenticPixels().
1594 % The format of the GetAuthenticPixelQueue() method is:
1596 % Quantum *GetAuthenticPixelQueue(const Image image)
1598 % A description of each parameter follows:
1600 % o image: the image.
1603 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1609 id = GetOpenMPThreadId();
1611 assert(image != (const Image *) NULL);
1612 assert(image->signature == MagickSignature);
1613 assert(image->cache != (Cache) NULL);
1614 cache_info=(CacheInfo *) image->cache;
1615 assert(cache_info->signature == MagickSignature);
1616 if (cache_info->methods.get_authentic_pixels_from_handler !=
1617 (GetAuthenticPixelsFromHandler) NULL)
1618 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1619 assert(id < (int) cache_info->number_threads);
1620 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1628 % G e t A u t h e n t i c P i x e l s %
1631 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1634 % region is successfully accessed, a pointer to a Quantum array
1635 % representing the region is returned, otherwise NULL is returned.
1637 % The returned pointer may point to a temporary working copy of the pixels
1638 % or it may point to the original pixels in memory. Performance is maximized
1639 % if the selected region is part of one row, or one or more full rows, since
1640 % then there is opportunity to access the pixels in-place (without a copy)
1641 % if the image is in memory, or in a memory-mapped file. The returned pointer
1642 % must *never* be deallocated by the user.
1644 % Pixels accessed via the returned pointer represent a simple array of type
1645 % Quantum. If the image has corresponding metacontent,call
1646 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1647 % meta-content corresponding to the region. Once the Quantum array has
1648 % been updated, the changes must be saved back to the underlying image using
1649 % SyncAuthenticPixels() or they may be lost.
1651 % The format of the GetAuthenticPixels() method is:
1653 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1654 % const ssize_t y,const size_t columns,const size_t rows,
1655 % ExceptionInfo *exception)
1657 % A description of each parameter follows:
1659 % o image: the image.
1661 % o x,y,columns,rows: These values define the perimeter of a region of
1664 % o exception: return any errors or warnings in this structure.
1667 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1668 const ssize_t y,const size_t columns,const size_t rows,
1669 ExceptionInfo *exception)
1675 id = GetOpenMPThreadId();
1680 assert(image != (Image *) NULL);
1681 assert(image->signature == MagickSignature);
1682 assert(image->cache != (Cache) NULL);
1683 cache_info=(CacheInfo *) image->cache;
1684 assert(cache_info->signature == MagickSignature);
1685 if (cache_info->methods.get_authentic_pixels_handler !=
1686 (GetAuthenticPixelsHandler) NULL)
1688 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1692 assert(id < (int) cache_info->number_threads);
1693 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1694 cache_info->nexus_info[id],exception);
1699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1703 + G e t A u t h e n t i c P i x e l s C a c h e %
1707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1709 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1710 % as defined by the geometry parameters. A pointer to the pixels is returned
1711 % if the pixels are transferred, otherwise a NULL is returned.
1713 % The format of the GetAuthenticPixelsCache() method is:
1715 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1716 % const ssize_t y,const size_t columns,const size_t rows,
1717 % ExceptionInfo *exception)
1719 % A description of each parameter follows:
1721 % o image: the image.
1723 % o x,y,columns,rows: These values define the perimeter of a region of
1726 % o exception: return any errors or warnings in this structure.
1729 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1730 const ssize_t y,const size_t columns,const size_t rows,
1731 ExceptionInfo *exception)
1737 id = GetOpenMPThreadId();
1742 assert(image != (const Image *) NULL);
1743 assert(image->signature == MagickSignature);
1744 assert(image->cache != (Cache) NULL);
1745 cache_info=(CacheInfo *) image->cache;
1746 if (cache_info == (Cache) NULL)
1747 return((Quantum *) NULL);
1748 assert(cache_info->signature == MagickSignature);
1749 assert(id < (int) cache_info->number_threads);
1750 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1751 cache_info->nexus_info[id],exception);
1756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760 + G e t I m a g e E x t e n t %
1764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1766 % GetImageExtent() returns the extent of the pixels associated corresponding
1767 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1769 % The format of the GetImageExtent() method is:
1771 % MagickSizeType GetImageExtent(const Image *image)
1773 % A description of each parameter follows:
1775 % o image: the image.
1778 MagickExport MagickSizeType GetImageExtent(const Image *image)
1784 id = GetOpenMPThreadId();
1786 assert(image != (Image *) NULL);
1787 assert(image->signature == MagickSignature);
1788 if (image->debug != MagickFalse)
1789 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1790 assert(image->cache != (Cache) NULL);
1791 cache_info=(CacheInfo *) image->cache;
1792 assert(cache_info->signature == MagickSignature);
1793 assert(id < (int) cache_info->number_threads);
1794 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802 + G e t I m a g e P i x e l C a c h e %
1806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1808 % GetImagePixelCache() ensures that there is only a single reference to the
1809 % pixel cache to be modified, updating the provided cache pointer to point to
1810 % a clone of the original pixel cache if necessary.
1812 % The format of the GetImagePixelCache method is:
1814 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1815 % ExceptionInfo *exception)
1817 % A description of each parameter follows:
1819 % o image: the image.
1821 % o clone: any value other than MagickFalse clones the cache pixels.
1823 % o exception: return any errors or warnings in this structure.
1827 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1837 Does the image match the pixel cache morphology?
1839 cache_info=(CacheInfo *) image->cache;
1840 p=image->channel_map;
1841 q=cache_info->channel_map;
1842 if ((image->storage_class != cache_info->storage_class) ||
1843 (image->colorspace != cache_info->colorspace) ||
1844 (image->matte != cache_info->matte) ||
1845 (image->mask != cache_info->mask) ||
1846 (image->columns != cache_info->columns) ||
1847 (image->rows != cache_info->rows) ||
1848 (image->number_channels != cache_info->number_channels) ||
1849 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1850 (image->metacontent_extent != cache_info->metacontent_extent) ||
1851 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1852 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1853 return(MagickFalse);
1857 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1858 ExceptionInfo *exception)
1867 static MagickSizeType
1873 cache_timestamp = 0;
1876 LockSemaphoreInfo(image->semaphore);
1877 if (cpu_throttle == 0)
1883 Set CPU throttle in milleseconds.
1885 cpu_throttle=MagickResourceInfinity;
1886 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1887 if (limit == (char *) NULL)
1888 limit=GetPolicyValue("throttle");
1889 if (limit != (char *) NULL)
1891 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1892 limit=DestroyString(limit);
1895 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1896 MagickDelay(cpu_throttle);
1897 if (time_limit == 0)
1900 Set the exire time in seconds.
1902 time_limit=GetMagickResourceLimit(TimeResource);
1903 cache_timestamp=time((time_t *) NULL);
1905 if ((time_limit != MagickResourceInfinity) &&
1906 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1907 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1908 assert(image->cache != (Cache) NULL);
1909 cache_info=(CacheInfo *) image->cache;
1910 destroy=MagickFalse;
1911 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1913 LockSemaphoreInfo(cache_info->semaphore);
1914 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1925 clone_image=(*image);
1926 clone_image.semaphore=AllocateSemaphoreInfo();
1927 clone_image.reference_count=1;
1928 clone_image.cache=ClonePixelCache(cache_info);
1929 clone_info=(CacheInfo *) clone_image.cache;
1930 status=OpenPixelCache(&clone_image,IOMode,exception);
1931 if (status != MagickFalse)
1933 if (clone != MagickFalse)
1934 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1935 if (status != MagickFalse)
1937 if (cache_info->mode == ReadMode)
1938 cache_info->nexus_info=(NexusInfo **) NULL;
1940 image->cache=clone_image.cache;
1943 DestroySemaphoreInfo(&clone_image.semaphore);
1945 UnlockSemaphoreInfo(cache_info->semaphore);
1947 if (destroy != MagickFalse)
1948 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1949 if (status != MagickFalse)
1952 Ensure the image matches the pixel cache morphology.
1954 image->taint=MagickTrue;
1955 image->type=UndefinedType;
1956 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1958 status=OpenPixelCache(image,IOMode,exception);
1959 cache_info=(CacheInfo *) image->cache;
1960 if (cache_info->type == DiskCache)
1961 (void) ClosePixelCacheOnDisk(cache_info);
1964 UnlockSemaphoreInfo(image->semaphore);
1965 if (status == MagickFalse)
1966 return((Cache) NULL);
1967 return(image->cache);
1971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1975 % G e t O n e A u t h e n t i c P i x e l %
1979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1981 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1982 % location. The image background color is returned if an error occurs.
1984 % The format of the GetOneAuthenticPixel() method is:
1986 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1987 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1989 % A description of each parameter follows:
1991 % o image: the image.
1993 % o x,y: These values define the location of the pixel to return.
1995 % o pixel: return a pixel at the specified (x,y) location.
1997 % o exception: return any errors or warnings in this structure.
2000 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2001 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2012 assert(image != (Image *) NULL);
2013 assert(image->signature == MagickSignature);
2014 assert(image->cache != (Cache) NULL);
2015 cache_info=(CacheInfo *) image->cache;
2016 assert(cache_info->signature == MagickSignature);
2017 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2018 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2019 (GetOneAuthenticPixelFromHandler) NULL)
2020 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2022 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2023 if (q == (Quantum *) NULL)
2025 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2026 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2027 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2028 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2029 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2030 return(MagickFalse);
2032 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2037 channel=GetPixelChannelMapChannel(image,i);
2038 pixel[channel]=q[i];
2044 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2048 + 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 %
2052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2054 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2055 % location. The image background color is returned if an error occurs.
2057 % The format of the GetOneAuthenticPixelFromCache() method is:
2059 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2060 % const ssize_t x,const ssize_t y,Quantum *pixel,
2061 % ExceptionInfo *exception)
2063 % A description of each parameter follows:
2065 % o image: the image.
2067 % o x,y: These values define the location of the pixel to return.
2069 % o pixel: return a pixel at the specified (x,y) location.
2071 % o exception: return any errors or warnings in this structure.
2074 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2075 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2081 id = GetOpenMPThreadId();
2089 assert(image != (const Image *) NULL);
2090 assert(image->signature == MagickSignature);
2091 assert(image->cache != (Cache) NULL);
2092 cache_info=(CacheInfo *) image->cache;
2093 assert(cache_info->signature == MagickSignature);
2094 assert(id < (int) cache_info->number_threads);
2095 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2096 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2098 if (q == (Quantum *) NULL)
2100 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2101 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2102 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2103 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2104 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2105 return(MagickFalse);
2107 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2112 channel=GetPixelChannelMapChannel(image,i);
2113 pixel[channel]=q[i];
2119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2123 % G e t O n e V i r t u a l P i x e l %
2127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2129 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2130 % (x,y) location. The image background color is returned if an error occurs.
2131 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2133 % The format of the GetOneVirtualPixel() method is:
2135 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2136 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2138 % A description of each parameter follows:
2140 % o image: the image.
2142 % o x,y: These values define the location of the pixel to return.
2144 % o pixel: return a pixel at the specified (x,y) location.
2146 % o exception: return any errors or warnings in this structure.
2149 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2150 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2156 id = GetOpenMPThreadId();
2164 assert(image != (const Image *) NULL);
2165 assert(image->signature == MagickSignature);
2166 assert(image->cache != (Cache) NULL);
2167 cache_info=(CacheInfo *) image->cache;
2168 assert(cache_info->signature == MagickSignature);
2169 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2170 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2171 (GetOneVirtualPixelFromHandler) NULL)
2172 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2173 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2174 assert(id < (int) cache_info->number_threads);
2175 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2176 1UL,1UL,cache_info->nexus_info[id],exception);
2177 if (p == (const Quantum *) NULL)
2179 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2180 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2181 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2182 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2183 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2184 return(MagickFalse);
2186 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2191 channel=GetPixelChannelMapChannel(image,i);
2192 pixel[channel]=p[i];
2198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2202 + 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 %
2206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2208 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2209 % specified (x,y) location. The image background color is returned if an
2212 % The format of the GetOneVirtualPixelFromCache() method is:
2214 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2215 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2216 % Quantum *pixel,ExceptionInfo *exception)
2218 % A description of each parameter follows:
2220 % o image: the image.
2222 % o virtual_pixel_method: the virtual pixel method.
2224 % o x,y: These values define the location of the pixel to return.
2226 % o pixel: return a pixel at the specified (x,y) location.
2228 % o exception: return any errors or warnings in this structure.
2231 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2232 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2233 Quantum *pixel,ExceptionInfo *exception)
2239 id = GetOpenMPThreadId();
2247 assert(image != (const Image *) NULL);
2248 assert(image->signature == MagickSignature);
2249 assert(image->cache != (Cache) NULL);
2250 cache_info=(CacheInfo *) image->cache;
2251 assert(cache_info->signature == MagickSignature);
2252 assert(id < (int) cache_info->number_threads);
2253 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2254 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2255 cache_info->nexus_info[id],exception);
2256 if (p == (const Quantum *) NULL)
2258 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2259 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2260 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2261 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2262 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2263 return(MagickFalse);
2265 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2270 channel=GetPixelChannelMapChannel(image,i);
2271 pixel[channel]=p[i];
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2281 % G e t O n e V i r t u a l P i x e l I n f o %
2285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2287 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2288 % location. The image background color is returned if an error occurs. If
2289 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2291 % The format of the GetOneVirtualPixelInfo() method is:
2293 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2294 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2295 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2297 % A description of each parameter follows:
2299 % o image: the image.
2301 % o virtual_pixel_method: the virtual pixel method.
2303 % o x,y: these values define the location of the pixel to return.
2305 % o pixel: return a pixel at the specified (x,y) location.
2307 % o exception: return any errors or warnings in this structure.
2310 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2311 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2312 PixelInfo *pixel,ExceptionInfo *exception)
2318 id = GetOpenMPThreadId();
2320 register const Quantum
2323 assert(image != (const Image *) NULL);
2324 assert(image->signature == MagickSignature);
2325 assert(image->cache != (Cache) NULL);
2326 cache_info=(CacheInfo *) image->cache;
2327 assert(cache_info->signature == MagickSignature);
2328 assert(id < (int) cache_info->number_threads);
2329 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2330 cache_info->nexus_info[id],exception);
2331 GetPixelInfo(image,pixel);
2332 if (p == (const Quantum *) NULL)
2333 return(MagickFalse);
2334 GetPixelInfoPixel(image,p,pixel);
2339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2343 + G e t P i x e l C a c h e C o l o r s p a c e %
2347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2349 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2351 % The format of the GetPixelCacheColorspace() method is:
2353 % Colorspace GetPixelCacheColorspace(Cache cache)
2355 % A description of each parameter follows:
2357 % o cache: the pixel cache.
2360 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2365 assert(cache != (Cache) NULL);
2366 cache_info=(CacheInfo *) cache;
2367 assert(cache_info->signature == MagickSignature);
2368 if (cache_info->debug != MagickFalse)
2369 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2370 cache_info->filename);
2371 return(cache_info->colorspace);
2375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2379 + G e t P i x e l C a c h e M e t h o d s %
2383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2385 % GetPixelCacheMethods() initializes the CacheMethods structure.
2387 % The format of the GetPixelCacheMethods() method is:
2389 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2391 % A description of each parameter follows:
2393 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2396 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2398 assert(cache_methods != (CacheMethods *) NULL);
2399 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2400 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2401 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2402 cache_methods->get_virtual_metacontent_from_handler=
2403 GetVirtualMetacontentFromCache;
2404 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2405 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2406 cache_methods->get_authentic_metacontent_from_handler=
2407 GetAuthenticMetacontentFromCache;
2408 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2409 cache_methods->get_one_authentic_pixel_from_handler=
2410 GetOneAuthenticPixelFromCache;
2411 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2412 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2413 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2421 + G e t P i x e l C a c h e N e x u s E x t e n t %
2425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2427 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2428 % corresponding with the last call to SetPixelCacheNexusPixels() or
2429 % GetPixelCacheNexusPixels().
2431 % The format of the GetPixelCacheNexusExtent() method is:
2433 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2434 % NexusInfo *nexus_info)
2436 % A description of each parameter follows:
2438 % o nexus_info: the nexus info.
2441 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2442 NexusInfo *nexus_info)
2450 assert(cache != NULL);
2451 cache_info=(CacheInfo *) cache;
2452 assert(cache_info->signature == MagickSignature);
2453 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2455 return((MagickSizeType) cache_info->columns*cache_info->rows);
2460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2464 + 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 %
2468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2470 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2473 % The format of the GetPixelCacheNexusMetacontent() method is:
2475 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2476 % NexusInfo *nexus_info)
2478 % A description of each parameter follows:
2480 % o cache: the pixel cache.
2482 % o nexus_info: the cache nexus to return the meta-content.
2485 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2486 NexusInfo *nexus_info)
2491 assert(cache != NULL);
2492 cache_info=(CacheInfo *) cache;
2493 assert(cache_info->signature == MagickSignature);
2494 if (cache_info->storage_class == UndefinedClass)
2495 return((void *) NULL);
2496 return(nexus_info->metacontent);
2500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2504 + G e t P i x e l C a c h e N e x u s P i x e l s %
2508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2510 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2513 % The format of the GetPixelCacheNexusPixels() method is:
2515 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2516 % NexusInfo *nexus_info)
2518 % A description of each parameter follows:
2520 % o cache: the pixel cache.
2522 % o nexus_info: the cache nexus to return the pixels.
2525 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2526 NexusInfo *nexus_info)
2531 assert(cache != NULL);
2532 cache_info=(CacheInfo *) cache;
2533 assert(cache_info->signature == MagickSignature);
2534 if (cache_info->storage_class == UndefinedClass)
2535 return((Quantum *) NULL);
2536 return(nexus_info->pixels);
2540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2544 + G e t P i x e l C a c h e P i x e l s %
2548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2550 % GetPixelCachePixels() returns the pixels associated with the specified image.
2552 % The format of the GetPixelCachePixels() method is:
2554 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2555 % ExceptionInfo *exception)
2557 % A description of each parameter follows:
2559 % o image: the image.
2561 % o length: the pixel cache length.
2563 % o exception: return any errors or warnings in this structure.
2566 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2567 ExceptionInfo *exception)
2572 assert(image != (const Image *) NULL);
2573 assert(image->signature == MagickSignature);
2574 assert(image->cache != (Cache) NULL);
2575 assert(length != (MagickSizeType *) NULL);
2576 assert(exception != (ExceptionInfo *) NULL);
2577 assert(exception->signature == MagickSignature);
2578 cache_info=(CacheInfo *) image->cache;
2579 assert(cache_info->signature == MagickSignature);
2581 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2582 return((void *) NULL);
2583 *length=cache_info->length;
2584 return((void *) cache_info->pixels);
2588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2592 + 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 %
2596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2598 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2600 % The format of the GetPixelCacheStorageClass() method is:
2602 % ClassType GetPixelCacheStorageClass(Cache cache)
2604 % A description of each parameter follows:
2606 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2608 % o cache: the pixel cache.
2611 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2616 assert(cache != (Cache) NULL);
2617 cache_info=(CacheInfo *) cache;
2618 assert(cache_info->signature == MagickSignature);
2619 if (cache_info->debug != MagickFalse)
2620 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2621 cache_info->filename);
2622 return(cache_info->storage_class);
2626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2630 + G e t P i x e l C a c h e T i l e S i z e %
2634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2636 % GetPixelCacheTileSize() returns the pixel cache tile size.
2638 % The format of the GetPixelCacheTileSize() method is:
2640 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2643 % A description of each parameter follows:
2645 % o image: the image.
2647 % o width: the optimize cache tile width in pixels.
2649 % o height: the optimize cache tile height in pixels.
2652 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2658 assert(image != (Image *) NULL);
2659 assert(image->signature == MagickSignature);
2660 if (image->debug != MagickFalse)
2661 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2662 cache_info=(CacheInfo *) image->cache;
2663 assert(cache_info->signature == MagickSignature);
2664 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2665 if (GetPixelCacheType(image) == DiskCache)
2666 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675 + G e t P i x e l C a c h e T y p e %
2679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2681 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2683 % The format of the GetPixelCacheType() method is:
2685 % CacheType GetPixelCacheType(const Image *image)
2687 % A description of each parameter follows:
2689 % o image: the image.
2692 MagickPrivate CacheType GetPixelCacheType(const Image *image)
2697 assert(image != (Image *) NULL);
2698 assert(image->signature == MagickSignature);
2699 assert(image->cache != (Cache) NULL);
2700 cache_info=(CacheInfo *) image->cache;
2701 assert(cache_info->signature == MagickSignature);
2702 return(cache_info->type);
2706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2710 + 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 %
2714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2716 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2717 % pixel cache. A virtual pixel is any pixel access that is outside the
2718 % boundaries of the image cache.
2720 % The format of the GetPixelCacheVirtualMethod() method is:
2722 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2724 % A description of each parameter follows:
2726 % o image: the image.
2729 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2734 assert(image != (Image *) NULL);
2735 assert(image->signature == MagickSignature);
2736 assert(image->cache != (Cache) NULL);
2737 cache_info=(CacheInfo *) image->cache;
2738 assert(cache_info->signature == MagickSignature);
2739 return(cache_info->virtual_pixel_method);
2743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2747 + 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 %
2751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2753 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2754 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2756 % The format of the GetVirtualMetacontentFromCache() method is:
2758 % void *GetVirtualMetacontentFromCache(const Image *image)
2760 % A description of each parameter follows:
2762 % o image: the image.
2765 static const void *GetVirtualMetacontentFromCache(const Image *image)
2771 id = GetOpenMPThreadId();
2776 assert(image != (const Image *) NULL);
2777 assert(image->signature == MagickSignature);
2778 assert(image->cache != (Cache) NULL);
2779 cache_info=(CacheInfo *) image->cache;
2780 assert(cache_info->signature == MagickSignature);
2781 assert(id < (int) cache_info->number_threads);
2782 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2783 cache_info->nexus_info[id]);
2784 return(metacontent);
2788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2792 + 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 %
2796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2798 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2801 % The format of the GetVirtualMetacontentFromNexus() method is:
2803 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2804 % NexusInfo *nexus_info)
2806 % A description of each parameter follows:
2808 % o cache: the pixel cache.
2810 % o nexus_info: the cache nexus to return the meta-content.
2813 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2814 NexusInfo *nexus_info)
2819 assert(cache != (Cache) NULL);
2820 cache_info=(CacheInfo *) cache;
2821 assert(cache_info->signature == MagickSignature);
2822 if (cache_info->storage_class == UndefinedClass)
2823 return((void *) NULL);
2824 return(nexus_info->metacontent);
2828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2832 % G e t V i r t u a l M e t a c o n t e n t %
2836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2839 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2840 % returned if the meta-content are not available.
2842 % The format of the GetVirtualMetacontent() method is:
2844 % const void *GetVirtualMetacontent(const Image *image)
2846 % A description of each parameter follows:
2848 % o image: the image.
2851 MagickExport const void *GetVirtualMetacontent(const Image *image)
2857 id = GetOpenMPThreadId();
2862 assert(image != (const Image *) NULL);
2863 assert(image->signature == MagickSignature);
2864 assert(image->cache != (Cache) NULL);
2865 cache_info=(CacheInfo *) image->cache;
2866 assert(cache_info->signature == MagickSignature);
2867 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2868 if (metacontent != (GetVirtualMetacontentFromHandler) NULL)
2869 return(metacontent);
2870 assert(id < (int) cache_info->number_threads);
2871 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2872 cache_info->nexus_info[id]);
2873 return(metacontent);
2877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2881 + 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 %
2885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2887 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2888 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2889 % is returned if the pixels are transferred, otherwise a NULL is returned.
2891 % The format of the GetVirtualPixelsFromNexus() method is:
2893 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2894 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2895 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2896 % ExceptionInfo *exception)
2898 % A description of each parameter follows:
2900 % o image: the image.
2902 % o virtual_pixel_method: the virtual pixel method.
2904 % o x,y,columns,rows: These values define the perimeter of a region of
2907 % o nexus_info: the cache nexus to acquire.
2909 % o exception: return any errors or warnings in this structure.
2916 0, 48, 12, 60, 3, 51, 15, 63,
2917 32, 16, 44, 28, 35, 19, 47, 31,
2918 8, 56, 4, 52, 11, 59, 7, 55,
2919 40, 24, 36, 20, 43, 27, 39, 23,
2920 2, 50, 14, 62, 1, 49, 13, 61,
2921 34, 18, 46, 30, 33, 17, 45, 29,
2922 10, 58, 6, 54, 9, 57, 5, 53,
2923 42, 26, 38, 22, 41, 25, 37, 21
2926 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2931 index=x+DitherMatrix[x & 0x07]-32L;
2934 if (index >= (ssize_t) columns)
2935 return((ssize_t) columns-1L);
2939 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2944 index=y+DitherMatrix[y & 0x07]-32L;
2947 if (index >= (ssize_t) rows)
2948 return((ssize_t) rows-1L);
2952 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2956 if (x >= (ssize_t) columns)
2957 return((ssize_t) (columns-1));
2961 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2965 if (y >= (ssize_t) rows)
2966 return((ssize_t) (rows-1));
2970 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2972 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2975 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2977 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2980 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2981 const size_t extent)
2987 Compute the remainder of dividing offset by extent. It returns not only
2988 the quotient (tile the offset falls in) but also the positive remainer
2989 within that tile such that 0 <= remainder < extent. This method is
2990 essentially a ldiv() using a floored modulo division rather than the
2991 normal default truncated modulo division.
2993 modulo.quotient=offset/(ssize_t) extent;
2996 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3000 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3001 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3002 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3003 ExceptionInfo *exception)
3020 virtual_pixel[CompositePixelChannel];
3025 register const Quantum
3038 register unsigned char
3045 *virtual_metacontent;
3050 assert(image != (const Image *) NULL);
3051 assert(image->signature == MagickSignature);
3052 assert(image->cache != (Cache) NULL);
3053 cache_info=(CacheInfo *) image->cache;
3054 assert(cache_info->signature == MagickSignature);
3055 if (cache_info->type == UndefinedCache)
3056 return((const Quantum *) NULL);
3059 region.width=columns;
3061 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3062 if (pixels == (Quantum *) NULL)
3063 return((const Quantum *) NULL);
3065 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3066 nexus_info->region.x;
3067 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3068 nexus_info->region.width-1L;
3069 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3070 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3071 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3072 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3078 Pixel request is inside cache extents.
3080 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3082 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3083 if (status == MagickFalse)
3084 return((const Quantum *) NULL);
3085 if (cache_info->metacontent_extent != 0)
3087 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3088 if (status == MagickFalse)
3089 return((const Quantum *) NULL);
3094 Pixel request is outside cache extents.
3096 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3097 virtual_nexus=AcquirePixelCacheNexus(1);
3098 if (virtual_nexus == (NexusInfo **) NULL)
3100 if (virtual_nexus != (NexusInfo **) NULL)
3101 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3102 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3103 "UnableToGetCacheNexus","`%s'",image->filename);
3104 return((const Quantum *) NULL);
3106 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3107 sizeof(*virtual_pixel));
3108 virtual_metacontent=(void *) NULL;
3109 switch (virtual_pixel_method)
3111 case BackgroundVirtualPixelMethod:
3112 case BlackVirtualPixelMethod:
3113 case GrayVirtualPixelMethod:
3114 case TransparentVirtualPixelMethod:
3115 case MaskVirtualPixelMethod:
3116 case WhiteVirtualPixelMethod:
3117 case EdgeVirtualPixelMethod:
3118 case CheckerTileVirtualPixelMethod:
3119 case HorizontalTileVirtualPixelMethod:
3120 case VerticalTileVirtualPixelMethod:
3122 if (cache_info->metacontent_extent != 0)
3125 Acquire a metacontent buffer.
3127 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3128 cache_info->metacontent_extent);
3129 if (virtual_metacontent == (void *) NULL)
3131 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3132 (void) ThrowMagickException(exception,GetMagickModule(),
3133 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3134 return((const Quantum *) NULL);
3136 (void) ResetMagickMemory(virtual_metacontent,0,
3137 cache_info->metacontent_extent);
3139 switch (virtual_pixel_method)
3141 case BlackVirtualPixelMethod:
3143 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3144 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3145 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3148 case GrayVirtualPixelMethod:
3150 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3151 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3153 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3156 case TransparentVirtualPixelMethod:
3158 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3159 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3160 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3163 case MaskVirtualPixelMethod:
3164 case WhiteVirtualPixelMethod:
3166 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3167 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3168 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3173 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3175 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3177 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3179 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3181 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3191 for (v=0; v < (ssize_t) rows; v++)
3193 for (u=0; u < (ssize_t) columns; u+=length)
3195 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3196 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3197 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3205 Transfer a single pixel.
3207 length=(MagickSizeType) 1;
3208 switch (virtual_pixel_method)
3212 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3213 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3214 1UL,1UL,*virtual_nexus,exception);
3215 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3218 case RandomVirtualPixelMethod:
3220 if (cache_info->random_info == (RandomInfo *) NULL)
3221 cache_info->random_info=AcquireRandomInfo();
3222 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3223 RandomX(cache_info->random_info,cache_info->columns),
3224 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3225 *virtual_nexus,exception);
3226 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3229 case DitherVirtualPixelMethod:
3231 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3232 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3233 1UL,1UL,*virtual_nexus,exception);
3234 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3237 case TileVirtualPixelMethod:
3239 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3240 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3241 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3242 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3244 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3247 case MirrorVirtualPixelMethod:
3249 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3250 if ((x_modulo.quotient & 0x01) == 1L)
3251 x_modulo.remainder=(ssize_t) cache_info->columns-
3252 x_modulo.remainder-1L;
3253 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3254 if ((y_modulo.quotient & 0x01) == 1L)
3255 y_modulo.remainder=(ssize_t) cache_info->rows-
3256 y_modulo.remainder-1L;
3257 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3258 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3260 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3263 case HorizontalTileEdgeVirtualPixelMethod:
3265 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3266 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3267 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3268 *virtual_nexus,exception);
3269 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3272 case VerticalTileEdgeVirtualPixelMethod:
3274 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3275 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3276 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3277 *virtual_nexus,exception);
3278 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3281 case BackgroundVirtualPixelMethod:
3282 case BlackVirtualPixelMethod:
3283 case GrayVirtualPixelMethod:
3284 case TransparentVirtualPixelMethod:
3285 case MaskVirtualPixelMethod:
3286 case WhiteVirtualPixelMethod:
3289 r=virtual_metacontent;
3292 case EdgeVirtualPixelMethod:
3293 case CheckerTileVirtualPixelMethod:
3295 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3296 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3297 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3300 r=virtual_metacontent;
3303 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3304 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3306 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3309 case HorizontalTileVirtualPixelMethod:
3311 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3314 r=virtual_metacontent;
3317 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3318 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3319 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3320 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3322 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3325 case VerticalTileVirtualPixelMethod:
3327 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3330 r=virtual_metacontent;
3333 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3334 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3335 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3336 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3338 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3342 if (p == (const Quantum *) NULL)
3344 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3346 q+=cache_info->number_channels;
3347 if ((s != (void *) NULL) && (r != (const void *) NULL))
3349 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3350 s+=cache_info->metacontent_extent;
3355 Transfer a run of pixels.
3357 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3358 length,1UL,*virtual_nexus,exception);
3359 if (p == (const Quantum *) NULL)
3361 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3362 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3363 q+=length*cache_info->number_channels;
3364 if ((r != (void *) NULL) && (s != (const void *) NULL))
3366 (void) memcpy(s,r,(size_t) length);
3367 s+=length*cache_info->metacontent_extent;
3374 if (virtual_metacontent != (void *) NULL)
3375 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3376 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3385 + G e t V i r t u a l P i x e l C a c h e %
3389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3391 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3392 % cache as defined by the geometry parameters. A pointer to the pixels
3393 % is returned if the pixels are transferred, otherwise a NULL is returned.
3395 % The format of the GetVirtualPixelCache() method is:
3397 % const Quantum *GetVirtualPixelCache(const Image *image,
3398 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3399 % const ssize_t y,const size_t columns,const size_t rows,
3400 % ExceptionInfo *exception)
3402 % A description of each parameter follows:
3404 % o image: the image.
3406 % o virtual_pixel_method: the virtual pixel method.
3408 % o x,y,columns,rows: These values define the perimeter of a region of
3411 % o exception: return any errors or warnings in this structure.
3414 static const Quantum *GetVirtualPixelCache(const Image *image,
3415 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3416 const size_t columns,const size_t rows,ExceptionInfo *exception)
3422 id = GetOpenMPThreadId();
3427 assert(image != (const Image *) NULL);
3428 assert(image->signature == MagickSignature);
3429 assert(image->cache != (Cache) NULL);
3430 cache_info=(CacheInfo *) image->cache;
3431 assert(cache_info->signature == MagickSignature);
3432 assert(id < (int) cache_info->number_threads);
3433 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3434 cache_info->nexus_info[id],exception);
3439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3443 % G e t V i r t u a l P i x e l Q u e u e %
3447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3449 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3450 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3452 % The format of the GetVirtualPixelQueue() method is:
3454 % const Quantum *GetVirtualPixelQueue(const Image image)
3456 % A description of each parameter follows:
3458 % o image: the image.
3461 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3467 id = GetOpenMPThreadId();
3469 assert(image != (const Image *) NULL);
3470 assert(image->signature == MagickSignature);
3471 assert(image->cache != (Cache) NULL);
3472 cache_info=(CacheInfo *) image->cache;
3473 assert(cache_info->signature == MagickSignature);
3474 if (cache_info->methods.get_virtual_pixels_handler !=
3475 (GetVirtualPixelsHandler) NULL)
3476 return(cache_info->methods.get_virtual_pixels_handler(image));
3477 assert(id < (int) cache_info->number_threads);
3478 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3486 % G e t V i r t u a l P i x e l s %
3490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3492 % GetVirtualPixels() returns an immutable pixel region. If the
3493 % region is successfully accessed, a pointer to it is returned, otherwise
3494 % NULL is returned. The returned pointer may point to a temporary working
3495 % copy of the pixels or it may point to the original pixels in memory.
3496 % Performance is maximized if the selected region is part of one row, or one
3497 % or more full rows, since there is opportunity to access the pixels in-place
3498 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3499 % returned pointer must *never* be deallocated by the user.
3501 % Pixels accessed via the returned pointer represent a simple array of type
3502 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3503 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3504 % access the meta-content (of type void) corresponding to the the
3507 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3509 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3510 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3511 % GetCacheViewAuthenticPixels() instead.
3513 % The format of the GetVirtualPixels() method is:
3515 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3516 % const ssize_t y,const size_t columns,const size_t rows,
3517 % ExceptionInfo *exception)
3519 % A description of each parameter follows:
3521 % o image: the image.
3523 % o x,y,columns,rows: These values define the perimeter of a region of
3526 % o exception: return any errors or warnings in this structure.
3529 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3530 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3531 ExceptionInfo *exception)
3537 id = GetOpenMPThreadId();
3542 assert(image != (const Image *) NULL);
3543 assert(image->signature == MagickSignature);
3544 assert(image->cache != (Cache) NULL);
3545 cache_info=(CacheInfo *) image->cache;
3546 assert(cache_info->signature == MagickSignature);
3547 if (cache_info->methods.get_virtual_pixel_handler !=
3548 (GetVirtualPixelHandler) NULL)
3549 return(cache_info->methods.get_virtual_pixel_handler(image,
3550 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3551 assert(id < (int) cache_info->number_threads);
3552 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3553 columns,rows,cache_info->nexus_info[id],exception);
3558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562 + 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 %
3566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3568 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3569 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3571 % The format of the GetVirtualPixelsCache() method is:
3573 % Quantum *GetVirtualPixelsCache(const Image *image)
3575 % A description of each parameter follows:
3577 % o image: the image.
3580 static const Quantum *GetVirtualPixelsCache(const Image *image)
3586 id = GetOpenMPThreadId();
3588 assert(image != (const Image *) NULL);
3589 assert(image->signature == MagickSignature);
3590 assert(image->cache != (Cache) NULL);
3591 cache_info=(CacheInfo *) image->cache;
3592 assert(cache_info->signature == MagickSignature);
3593 assert(id < (int) cache_info->number_threads);
3594 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3602 + G e t V i r t u a l P i x e l s N e x u s %
3606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3608 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3611 % The format of the GetVirtualPixelsNexus() method is:
3613 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3614 % NexusInfo *nexus_info)
3616 % A description of each parameter follows:
3618 % o cache: the pixel cache.
3620 % o nexus_info: the cache nexus to return the colormap pixels.
3623 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3624 NexusInfo *nexus_info)
3629 assert(cache != (Cache) NULL);
3630 cache_info=(CacheInfo *) cache;
3631 assert(cache_info->signature == MagickSignature);
3632 if (cache_info->storage_class == UndefinedClass)
3633 return((Quantum *) NULL);
3634 return((const Quantum *) nexus_info->pixels);
3638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3642 + O p e n P i x e l C a c h e %
3646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3648 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3649 % dimensions, allocating space for the image pixels and optionally the
3650 % metacontent, and memory mapping the cache if it is disk based. The cache
3651 % nexus array is initialized as well.
3653 % The format of the OpenPixelCache() method is:
3655 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3656 % ExceptionInfo *exception)
3658 % A description of each parameter follows:
3660 % o image: the image.
3662 % o mode: ReadMode, WriteMode, or IOMode.
3664 % o exception: return any errors or warnings in this structure.
3668 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3670 cache_info->mapped=MagickFalse;
3671 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3672 cache_info->length);
3673 if (cache_info->pixels == (Quantum *) NULL)
3675 cache_info->mapped=MagickTrue;
3676 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3677 cache_info->length);
3681 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3691 cache_info=(CacheInfo *) image->cache;
3692 if (image->debug != MagickFalse)
3695 format[MaxTextExtent],
3696 message[MaxTextExtent];
3698 (void) FormatMagickSize(length,MagickFalse,format);
3699 (void) FormatLocaleString(message,MaxTextExtent,
3700 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3701 cache_info->cache_filename,cache_info->file,format);
3702 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3704 if (length != (MagickSizeType) ((MagickOffsetType) length))
3705 return(MagickFalse);
3706 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3708 return(MagickFalse);
3709 if ((MagickSizeType) extent >= length)
3711 offset=(MagickOffsetType) length-1;
3712 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3713 return(count == (MagickOffsetType) 1 ? MagickTrue : 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->matte=image->matte;
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,®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 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4394 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4395 cache_info->cache_filename);
4396 return(MagickFalse);
4398 if ((cache_info->columns == nexus_info->region.width) &&
4399 (extent <= MagickMaxBufferExtent))
4404 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4405 for (y=0; y < (ssize_t) rows; y++)
4407 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4408 cache_info->number_channels*sizeof(Quantum)+offset*
4409 cache_info->metacontent_extent,length,(unsigned char *) q);
4410 if ((MagickSizeType) count != length)
4412 offset+=cache_info->columns;
4413 q+=cache_info->metacontent_extent*nexus_info->region.width;
4415 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4416 (void) ClosePixelCacheOnDisk(cache_info);
4417 if (y < (ssize_t) rows)
4419 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4420 cache_info->cache_filename);
4421 return(MagickFalse);
4428 if ((cache_info->debug != MagickFalse) &&
4429 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4430 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4431 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4432 nexus_info->region.width,(double) nexus_info->region.height,(double)
4433 nexus_info->region.x,(double) nexus_info->region.y);
4438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4442 + R e a d P i x e l C a c h e P i x e l s %
4446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4448 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4451 % The format of the ReadPixelCachePixels() method is:
4453 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4454 % NexusInfo *nexus_info,ExceptionInfo *exception)
4456 % A description of each parameter follows:
4458 % o cache_info: the pixel cache.
4460 % o nexus_info: the cache nexus to read the pixels.
4462 % o exception: return any errors or warnings in this structure.
4465 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4466 NexusInfo *nexus_info,ExceptionInfo *exception)
4485 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4487 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4488 nexus_info->region.x;
4489 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4491 rows=nexus_info->region.height;
4493 q=nexus_info->pixels;
4494 switch (cache_info->type)
4503 Read pixels from memory.
4505 if ((cache_info->columns == nexus_info->region.width) &&
4506 (extent == (MagickSizeType) ((size_t) extent)))
4511 p=cache_info->pixels+offset*cache_info->number_channels;
4512 for (y=0; y < (ssize_t) rows; y++)
4514 (void) memcpy(q,p,(size_t) length);
4515 p+=cache_info->number_channels*cache_info->columns;
4516 q+=cache_info->number_channels*nexus_info->region.width;
4523 Read pixels from disk.
4525 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4527 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4528 cache_info->cache_filename);
4529 return(MagickFalse);
4531 if ((cache_info->columns == nexus_info->region.width) &&
4532 (extent <= MagickMaxBufferExtent))
4537 for (y=0; y < (ssize_t) rows; y++)
4539 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4540 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4541 if ((MagickSizeType) count != length)
4543 offset+=cache_info->columns;
4544 q+=cache_info->number_channels*nexus_info->region.width;
4546 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4547 (void) ClosePixelCacheOnDisk(cache_info);
4548 if (y < (ssize_t) rows)
4550 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4551 cache_info->cache_filename);
4552 return(MagickFalse);
4559 if ((cache_info->debug != MagickFalse) &&
4560 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4561 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4562 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4563 nexus_info->region.width,(double) nexus_info->region.height,(double)
4564 nexus_info->region.x,(double) nexus_info->region.y);
4569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4573 + R e f e r e n c e P i x e l C a c h e %
4577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4579 % ReferencePixelCache() increments the reference count associated with the
4580 % pixel cache returning a pointer to the cache.
4582 % The format of the ReferencePixelCache method is:
4584 % Cache ReferencePixelCache(Cache cache_info)
4586 % A description of each parameter follows:
4588 % o cache_info: the pixel cache.
4591 MagickPrivate Cache ReferencePixelCache(Cache cache)
4596 assert(cache != (Cache *) NULL);
4597 cache_info=(CacheInfo *) cache;
4598 assert(cache_info->signature == MagickSignature);
4599 LockSemaphoreInfo(cache_info->semaphore);
4600 cache_info->reference_count++;
4601 UnlockSemaphoreInfo(cache_info->semaphore);
4606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4610 + S e t P i x e l C a c h e M e t h o d s %
4614 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4616 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4618 % The format of the SetPixelCacheMethods() method is:
4620 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4622 % A description of each parameter follows:
4624 % o cache: the pixel cache.
4626 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4629 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4634 GetOneAuthenticPixelFromHandler
4635 get_one_authentic_pixel_from_handler;
4637 GetOneVirtualPixelFromHandler
4638 get_one_virtual_pixel_from_handler;
4641 Set cache pixel methods.
4643 assert(cache != (Cache) NULL);
4644 assert(cache_methods != (CacheMethods *) NULL);
4645 cache_info=(CacheInfo *) cache;
4646 assert(cache_info->signature == MagickSignature);
4647 if (cache_info->debug != MagickFalse)
4648 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4649 cache_info->filename);
4650 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4651 cache_info->methods.get_virtual_pixel_handler=
4652 cache_methods->get_virtual_pixel_handler;
4653 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4654 cache_info->methods.destroy_pixel_handler=
4655 cache_methods->destroy_pixel_handler;
4656 if (cache_methods->get_virtual_metacontent_from_handler !=
4657 (GetVirtualMetacontentFromHandler) NULL)
4658 cache_info->methods.get_virtual_metacontent_from_handler=
4659 cache_methods->get_virtual_metacontent_from_handler;
4660 if (cache_methods->get_authentic_pixels_handler !=
4661 (GetAuthenticPixelsHandler) NULL)
4662 cache_info->methods.get_authentic_pixels_handler=
4663 cache_methods->get_authentic_pixels_handler;
4664 if (cache_methods->queue_authentic_pixels_handler !=
4665 (QueueAuthenticPixelsHandler) NULL)
4666 cache_info->methods.queue_authentic_pixels_handler=
4667 cache_methods->queue_authentic_pixels_handler;
4668 if (cache_methods->sync_authentic_pixels_handler !=
4669 (SyncAuthenticPixelsHandler) NULL)
4670 cache_info->methods.sync_authentic_pixels_handler=
4671 cache_methods->sync_authentic_pixels_handler;
4672 if (cache_methods->get_authentic_pixels_from_handler !=
4673 (GetAuthenticPixelsFromHandler) NULL)
4674 cache_info->methods.get_authentic_pixels_from_handler=
4675 cache_methods->get_authentic_pixels_from_handler;
4676 if (cache_methods->get_authentic_metacontent_from_handler !=
4677 (GetAuthenticMetacontentFromHandler) NULL)
4678 cache_info->methods.get_authentic_metacontent_from_handler=
4679 cache_methods->get_authentic_metacontent_from_handler;
4680 get_one_virtual_pixel_from_handler=
4681 cache_info->methods.get_one_virtual_pixel_from_handler;
4682 if (get_one_virtual_pixel_from_handler !=
4683 (GetOneVirtualPixelFromHandler) NULL)
4684 cache_info->methods.get_one_virtual_pixel_from_handler=
4685 cache_methods->get_one_virtual_pixel_from_handler;
4686 get_one_authentic_pixel_from_handler=
4687 cache_methods->get_one_authentic_pixel_from_handler;
4688 if (get_one_authentic_pixel_from_handler !=
4689 (GetOneAuthenticPixelFromHandler) NULL)
4690 cache_info->methods.get_one_authentic_pixel_from_handler=
4691 cache_methods->get_one_authentic_pixel_from_handler;
4695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4699 + S e t P i x e l C a c h e N e x u s P i x e l s %
4703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4705 % SetPixelCacheNexusPixels() defines the region of the cache for the
4706 % specified cache nexus.
4708 % The format of the SetPixelCacheNexusPixels() method is:
4710 % Quantum SetPixelCacheNexusPixels(const Image *image,
4711 % const RectangleInfo *region,NexusInfo *nexus_info,
4712 % ExceptionInfo *exception)
4714 % A description of each parameter follows:
4716 % o image: the image.
4718 % o region: A pointer to the RectangleInfo structure that defines the
4719 % region of this particular cache nexus.
4721 % o nexus_info: the cache nexus to set.
4723 % o exception: return any errors or warnings in this structure.
4727 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4728 NexusInfo *nexus_info,ExceptionInfo *exception)
4730 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4731 return(MagickFalse);
4732 nexus_info->mapped=MagickFalse;
4733 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
4734 nexus_info->length);
4735 if (nexus_info->cache == (Quantum *) NULL)
4737 nexus_info->mapped=MagickTrue;
4738 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4739 nexus_info->length);
4741 if (nexus_info->cache == (Quantum *) NULL)
4743 (void) ThrowMagickException(exception,GetMagickModule(),
4744 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4745 cache_info->filename);
4746 return(MagickFalse);
4751 static Quantum *SetPixelCacheNexusPixels(const Image *image,
4752 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4764 cache_info=(CacheInfo *) image->cache;
4765 assert(cache_info->signature == MagickSignature);
4766 if (cache_info->type == UndefinedCache)
4767 return((Quantum *) NULL);
4768 nexus_info->region=(*region);
4769 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
4775 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4776 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4777 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4778 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4779 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4780 ((nexus_info->region.width == cache_info->columns) ||
4781 ((nexus_info->region.width % cache_info->columns) == 0)))))
4787 Pixels are accessed directly from memory.
4789 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4790 nexus_info->region.x;
4791 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4793 nexus_info->metacontent=(void *) NULL;
4794 if (cache_info->metacontent_extent != 0)
4795 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4796 offset*cache_info->metacontent_extent;
4797 return(nexus_info->pixels);
4801 Pixels are stored in a cache region until they are synced to the cache.
4803 number_pixels=(MagickSizeType) nexus_info->region.width*
4804 nexus_info->region.height;
4805 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4806 if (cache_info->metacontent_extent != 0)
4807 length+=number_pixels*cache_info->metacontent_extent;
4808 if (nexus_info->cache == (Quantum *) NULL)
4810 nexus_info->length=length;
4811 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4812 if (status == MagickFalse)
4814 nexus_info->length=0;
4815 return((Quantum *) NULL);
4819 if (nexus_info->length != length)
4821 RelinquishCacheNexusPixels(nexus_info);
4822 nexus_info->length=length;
4823 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4824 if (status == MagickFalse)
4826 nexus_info->length=0;
4827 return((Quantum *) NULL);
4830 nexus_info->pixels=nexus_info->cache;
4831 nexus_info->metacontent=(void *) NULL;
4832 if (cache_info->metacontent_extent != 0)
4833 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4834 cache_info->number_channels);
4835 return(nexus_info->pixels);
4839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4843 % 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 %
4847 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4849 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4850 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4851 % access that is outside the boundaries of the image cache.
4853 % The format of the SetPixelCacheVirtualMethod() method is:
4855 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4856 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4858 % A description of each parameter follows:
4860 % o image: the image.
4862 % o virtual_pixel_method: choose the type of virtual pixel.
4864 % o exception: return any errors or warnings in this structure.
4868 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4869 ExceptionInfo *exception)
4883 assert(image != (Image *) NULL);
4884 assert(image->signature == MagickSignature);
4885 if (image->debug != MagickFalse)
4886 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4887 assert(image->cache != (Cache) NULL);
4888 cache_info=(CacheInfo *) image->cache;
4889 assert(cache_info->signature == MagickSignature);
4890 image->matte=MagickTrue;
4892 image_view=AcquireCacheView(image);
4893 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4894 #pragma omp parallel for schedule(static,4) shared(status)
4896 for (y=0; y < (ssize_t) image->rows; y++)
4904 if (status == MagickFalse)
4906 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4907 if (q == (Quantum *) NULL)
4912 for (x=0; x < (ssize_t) image->columns; x++)
4914 SetPixelAlpha(image,alpha,q);
4915 q+=GetPixelChannels(image);
4917 status=SyncCacheViewAuthenticPixels(image_view,exception);
4919 image_view=DestroyCacheView(image_view);
4923 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4924 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4932 assert(image != (Image *) NULL);
4933 assert(image->signature == MagickSignature);
4934 if (image->debug != MagickFalse)
4935 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4936 assert(image->cache != (Cache) NULL);
4937 cache_info=(CacheInfo *) image->cache;
4938 assert(cache_info->signature == MagickSignature);
4939 method=cache_info->virtual_pixel_method;
4940 cache_info->virtual_pixel_method=virtual_pixel_method;
4941 switch (virtual_pixel_method)
4943 case BackgroundVirtualPixelMethod:
4945 if ((image->background_color.matte != MagickFalse) &&
4946 (image->matte == MagickFalse))
4947 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4950 case TransparentVirtualPixelMethod:
4952 if (image->matte == MagickFalse)
4953 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4967 + 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 %
4971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4973 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4974 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4975 % is synced, otherwise MagickFalse.
4977 % The format of the SyncAuthenticPixelCacheNexus() method is:
4979 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4980 % NexusInfo *nexus_info,ExceptionInfo *exception)
4982 % A description of each parameter follows:
4984 % o image: the image.
4986 % o nexus_info: the cache nexus to sync.
4988 % o exception: return any errors or warnings in this structure.
4991 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4992 NexusInfo *nexus_info,ExceptionInfo *exception)
5001 Transfer pixels to the cache.
5003 assert(image != (Image *) NULL);
5004 assert(image->signature == MagickSignature);
5005 if (image->cache == (Cache) NULL)
5006 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5007 cache_info=(CacheInfo *) image->cache;
5008 assert(cache_info->signature == MagickSignature);
5009 if (cache_info->type == UndefinedCache)
5010 return(MagickFalse);
5011 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5013 assert(cache_info->signature == MagickSignature);
5014 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5015 if ((cache_info->metacontent_extent != 0) &&
5016 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5017 return(MagickFalse);
5022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5026 + S y n c A u t h e n t i c P i x e l C a c h e %
5030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5032 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5033 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5034 % otherwise MagickFalse.
5036 % The format of the SyncAuthenticPixelsCache() method is:
5038 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5039 % ExceptionInfo *exception)
5041 % A description of each parameter follows:
5043 % o image: the image.
5045 % o exception: return any errors or warnings in this structure.
5048 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5049 ExceptionInfo *exception)
5055 id = GetOpenMPThreadId();
5060 assert(image != (Image *) NULL);
5061 assert(image->signature == MagickSignature);
5062 assert(image->cache != (Cache) NULL);
5063 cache_info=(CacheInfo *) image->cache;
5064 assert(cache_info->signature == MagickSignature);
5065 assert(id < (int) cache_info->number_threads);
5066 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5076 % S y n c A u t h e n t i c P i x e l s %
5080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5082 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5083 % The method returns MagickTrue if the pixel region is flushed, otherwise
5086 % The format of the SyncAuthenticPixels() method is:
5088 % MagickBooleanType SyncAuthenticPixels(Image *image,
5089 % ExceptionInfo *exception)
5091 % A description of each parameter follows:
5093 % o image: the image.
5095 % o exception: return any errors or warnings in this structure.
5098 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5099 ExceptionInfo *exception)
5105 id = GetOpenMPThreadId();
5110 assert(image != (Image *) NULL);
5111 assert(image->signature == MagickSignature);
5112 assert(image->cache != (Cache) NULL);
5113 cache_info=(CacheInfo *) image->cache;
5114 assert(cache_info->signature == MagickSignature);
5115 if (cache_info->methods.sync_authentic_pixels_handler !=
5116 (SyncAuthenticPixelsHandler) NULL)
5118 status=cache_info->methods.sync_authentic_pixels_handler(image,
5122 assert(id < (int) cache_info->number_threads);
5123 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5133 + S y n c I m a g e P i x e l C a c h e %
5137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5139 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5140 % The method returns MagickTrue if the pixel region is flushed, otherwise
5143 % The format of the SyncImagePixelCache() method is:
5145 % MagickBooleanType SyncImagePixelCache(Image *image,
5146 % ExceptionInfo *exception)
5148 % A description of each parameter follows:
5150 % o image: the image.
5152 % o exception: return any errors or warnings in this structure.
5155 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5156 ExceptionInfo *exception)
5161 assert(image != (Image *) NULL);
5162 assert(exception != (ExceptionInfo *) NULL);
5163 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5164 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5172 + 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 %
5176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5178 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5179 % of the pixel cache.
5181 % The format of the WritePixelCacheMetacontent() method is:
5183 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5184 % NexusInfo *nexus_info,ExceptionInfo *exception)
5186 % A description of each parameter follows:
5188 % o cache_info: the pixel cache.
5190 % o nexus_info: the cache nexus to write the meta-content.
5192 % o exception: return any errors or warnings in this structure.
5195 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5196 NexusInfo *nexus_info,ExceptionInfo *exception)
5206 register const unsigned char
5215 if (cache_info->metacontent_extent == 0)
5216 return(MagickFalse);
5217 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5219 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5220 nexus_info->region.x;
5221 length=(MagickSizeType) nexus_info->region.width*
5222 cache_info->metacontent_extent;
5223 rows=nexus_info->region.height;
5224 extent=(MagickSizeType) length*rows;
5225 p=(unsigned char *) nexus_info->metacontent;
5226 switch (cache_info->type)
5231 register unsigned char
5235 Write associated pixels to memory.
5237 if ((cache_info->columns == nexus_info->region.width) &&
5238 (extent == (MagickSizeType) ((size_t) extent)))
5243 q=(unsigned char *) cache_info->metacontent+offset*
5244 cache_info->metacontent_extent;
5245 for (y=0; y < (ssize_t) rows; y++)
5247 (void) memcpy(q,p,(size_t) length);
5248 p+=nexus_info->region.width*cache_info->metacontent_extent;
5249 q+=cache_info->columns*cache_info->metacontent_extent;
5256 Write associated pixels to disk.
5258 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5260 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5261 cache_info->cache_filename);
5262 return(MagickFalse);
5264 if ((cache_info->columns == nexus_info->region.width) &&
5265 (extent <= MagickMaxBufferExtent))
5270 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5271 for (y=0; y < (ssize_t) rows; y++)
5273 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5274 cache_info->number_channels*sizeof(Quantum)+offset*
5275 cache_info->metacontent_extent,length,(const unsigned char *) p);
5276 if ((MagickSizeType) count != length)
5278 p+=nexus_info->region.width*cache_info->metacontent_extent;
5279 offset+=cache_info->columns;
5281 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5282 (void) ClosePixelCacheOnDisk(cache_info);
5283 if (y < (ssize_t) rows)
5285 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5286 cache_info->cache_filename);
5287 return(MagickFalse);
5294 if ((cache_info->debug != MagickFalse) &&
5295 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5296 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5297 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5298 nexus_info->region.width,(double) nexus_info->region.height,(double)
5299 nexus_info->region.x,(double) nexus_info->region.y);
5304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5308 + W r i t e C a c h e P i x e l s %
5312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5314 % WritePixelCachePixels() writes image pixels to the specified region of the
5317 % The format of the WritePixelCachePixels() method is:
5319 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5320 % NexusInfo *nexus_info,ExceptionInfo *exception)
5322 % A description of each parameter follows:
5324 % o cache_info: the pixel cache.
5326 % o nexus_info: the cache nexus to write the pixels.
5328 % o exception: return any errors or warnings in this structure.
5331 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5332 NexusInfo *nexus_info,ExceptionInfo *exception)
5342 register const Quantum
5351 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5353 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5354 nexus_info->region.x;
5355 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5357 rows=nexus_info->region.height;
5359 p=nexus_info->pixels;
5360 switch (cache_info->type)
5369 Write pixels to memory.
5371 if ((cache_info->columns == nexus_info->region.width) &&
5372 (extent == (MagickSizeType) ((size_t) extent)))
5377 q=cache_info->pixels+offset*cache_info->number_channels;
5378 for (y=0; y < (ssize_t) rows; y++)
5380 (void) memcpy(q,p,(size_t) length);
5381 p+=nexus_info->region.width*cache_info->number_channels;
5382 q+=cache_info->columns*cache_info->number_channels;
5389 Write pixels to disk.
5391 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5393 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5394 cache_info->cache_filename);
5395 return(MagickFalse);
5397 if ((cache_info->columns == nexus_info->region.width) &&
5398 (extent <= MagickMaxBufferExtent))
5403 for (y=0; y < (ssize_t) rows; y++)
5405 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5406 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5408 if ((MagickSizeType) count != length)
5410 p+=nexus_info->region.width*cache_info->number_channels;
5411 offset+=cache_info->columns;
5413 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5414 (void) ClosePixelCacheOnDisk(cache_info);
5415 if (y < (ssize_t) rows)
5417 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5418 cache_info->cache_filename);
5419 return(MagickFalse);
5426 if ((cache_info->debug != MagickFalse) &&
5427 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5428 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5429 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5430 nexus_info->region.width,(double) nexus_info->region.height,(double)
5431 nexus_info->region.x,(double) nexus_info->region.y);