2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/composite-private.h"
50 #include "MagickCore/exception.h"
51 #include "MagickCore/exception-private.h"
52 #include "MagickCore/geometry.h"
53 #include "MagickCore/list.h"
54 #include "MagickCore/log.h"
55 #include "MagickCore/magick.h"
56 #include "MagickCore/memory_.h"
57 #include "MagickCore/pixel.h"
58 #include "MagickCore/pixel-accessor.h"
59 #include "MagickCore/policy.h"
60 #include "MagickCore/quantum.h"
61 #include "MagickCore/random_.h"
62 #include "MagickCore/resource_.h"
63 #include "MagickCore/semaphore.h"
64 #include "MagickCore/splay-tree.h"
65 #include "MagickCore/string_.h"
66 #include "MagickCore/string-private.h"
67 #include "MagickCore/thread-private.h"
68 #include "MagickCore/utility.h"
69 #include "MagickCore/utility-private.h"
70 #if defined(MAGICKCORE_ZLIB_DELEGATE)
77 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
78 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
79 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
84 typedef struct _MagickModulo
114 Forward declarations.
116 #if defined(__cplusplus) || defined(c_plusplus)
121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
123 *GetVirtualPixelsCache(const Image *);
126 *GetVirtualMetacontentFromCache(const Image *);
128 static MagickBooleanType
129 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
130 Quantum *,ExceptionInfo *),
131 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
132 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
133 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
134 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
136 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
137 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
138 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
141 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
143 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
144 const size_t,ExceptionInfo *),
145 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
148 #if defined(__cplusplus) || defined(c_plusplus)
155 static volatile MagickBooleanType
156 instantiate_cache = MagickFalse;
159 *cache_semaphore = (SemaphoreInfo *) NULL;
162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166 + A c q u i r e P i x e l C a c h e %
170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 % AcquirePixelCache() acquires a pixel cache.
174 % The format of the AcquirePixelCache() method is:
176 % Cache AcquirePixelCache(const size_t number_threads)
178 % A description of each parameter follows:
180 % o number_threads: the number of nexus threads.
183 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
188 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
193 cache_info->mode=IOMode;
194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
203 cache_info->semaphore=AllocateSemaphoreInfo();
204 cache_info->reference_count=1;
205 cache_info->disk_semaphore=AllocateSemaphoreInfo();
206 cache_info->debug=IsEventLogging();
207 cache_info->signature=MagickSignature;
208 return((Cache ) cache_info);
212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216 % A c q u i r e P i x e l C a c h e N e x u s %
220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
224 % The format of the AcquirePixelCacheNexus method is:
226 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
228 % A description of each parameter follows:
230 % o number_threads: the number of nexus threads.
233 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
241 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
242 sizeof(*nexus_info));
243 if (nexus_info == (NexusInfo **) NULL)
244 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
245 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
246 sizeof(**nexus_info));
247 if (nexus_info[0] == (NexusInfo *) NULL)
248 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
249 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
250 for (i=0; i < (ssize_t) number_threads; i++)
252 nexus_info[i]=(&nexus_info[0][i]);
253 nexus_info[i]->signature=MagickSignature;
259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
263 + A c q u i r e P i x e l C a c h e P i x e l s %
267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269 % AcquirePixelCachePixels() returns the pixels associated with the specified
272 % The format of the AcquirePixelCachePixels() method is:
274 % const void *AcquirePixelCachePixels(const Image *image,
275 % MagickSizeType *length,ExceptionInfo *exception)
277 % A description of each parameter follows:
279 % o image: the image.
281 % o length: the pixel cache length.
283 % o exception: return any errors or warnings in this structure.
286 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
287 MagickSizeType *length,ExceptionInfo *exception)
292 assert(image != (const Image *) NULL);
293 assert(image->signature == MagickSignature);
294 assert(exception != (ExceptionInfo *) NULL);
295 assert(exception->signature == MagickSignature);
296 assert(image->cache != (Cache) NULL);
297 cache_info=(CacheInfo *) image->cache;
298 assert(cache_info->signature == MagickSignature);
300 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
301 return((const void *) NULL);
302 *length=cache_info->length;
303 return((const void *) cache_info->pixels);
307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
311 + C a c h e C o m p o n e n t G e n e s i s %
315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317 % CacheComponentGenesis() instantiates the cache component.
319 % The format of the CacheComponentGenesis method is:
321 % MagickBooleanType CacheComponentGenesis(void)
324 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
326 AcquireSemaphoreInfo(&cache_semaphore);
331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335 + C a c h e C o m p o n e n t T e r m i n u s %
339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341 % CacheComponentTerminus() destroys the cache component.
343 % The format of the CacheComponentTerminus() method is:
345 % CacheComponentTerminus(void)
348 MagickPrivate void CacheComponentTerminus(void)
350 if (cache_semaphore == (SemaphoreInfo *) NULL)
351 AcquireSemaphoreInfo(&cache_semaphore);
352 LockSemaphoreInfo(cache_semaphore);
353 instantiate_cache=MagickFalse;
354 UnlockSemaphoreInfo(cache_semaphore);
355 DestroySemaphoreInfo(&cache_semaphore);
359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363 + C l o n e P i x e l C a c h e %
367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
369 % ClonePixelCache() clones a pixel cache.
371 % The format of the ClonePixelCache() method is:
373 % Cache ClonePixelCache(const Cache cache)
375 % A description of each parameter follows:
377 % o cache: the pixel cache.
380 MagickPrivate Cache ClonePixelCache(const Cache cache)
388 assert(cache != NULL);
389 cache_info=(const CacheInfo *) cache;
390 assert(cache_info->signature == MagickSignature);
391 if (cache_info->debug != MagickFalse)
392 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
393 cache_info->filename);
394 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
395 if (clone_info == (Cache) NULL)
396 return((Cache) NULL);
397 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
398 return((Cache ) clone_info);
402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
406 + C l o n e P i x e l C a c h e P i x e l s %
410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
411 % ClonePixelCachePixels() clones the source pixel cache to the destination
414 % The format of the ClonePixelCachePixels() method is:
416 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
417 % CacheInfo *source_info,ExceptionInfo *exception)
419 % A description of each parameter follows:
421 % o cache_info: the pixel cache.
423 % o source_info: the source pixel cache.
425 % o exception: return any errors or warnings in this structure.
429 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
435 LockSemaphoreInfo(cache_info->disk_semaphore);
436 if (cache_info->file != -1)
438 status=close(cache_info->file);
439 cache_info->file=(-1);
440 RelinquishMagickResource(FileResource,1);
442 UnlockSemaphoreInfo(cache_info->disk_semaphore);
443 return(status == -1 ? MagickFalse : MagickTrue);
446 static inline MagickSizeType MagickMax(const MagickSizeType x,
447 const MagickSizeType y)
454 static inline MagickSizeType MagickMin(const MagickSizeType x,
455 const MagickSizeType y)
462 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
469 Open pixel cache on disk.
471 LockSemaphoreInfo(cache_info->disk_semaphore);
472 if (cache_info->file != -1)
474 UnlockSemaphoreInfo(cache_info->disk_semaphore);
475 return(MagickTrue); /* cache already open */
477 if (*cache_info->cache_filename == '\0')
478 file=AcquireUniqueFileResource(cache_info->cache_filename);
484 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
489 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
490 O_BINARY | O_EXCL,S_MODE);
492 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
498 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
501 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
507 UnlockSemaphoreInfo(cache_info->disk_semaphore);
510 (void) AcquireMagickResource(FileResource,1);
511 cache_info->file=file;
512 cache_info->mode=mode;
513 cache_info->timestamp=time(0);
514 UnlockSemaphoreInfo(cache_info->disk_semaphore);
518 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
519 const MagickOffsetType offset,const MagickSizeType length,
520 unsigned char *restrict buffer)
522 register MagickOffsetType
528 cache_info->timestamp=time(0);
529 #if !defined(MAGICKCORE_HAVE_PREAD)
530 LockSemaphoreInfo(cache_info->disk_semaphore);
531 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
533 UnlockSemaphoreInfo(cache_info->disk_semaphore);
534 return((MagickOffsetType) -1);
538 for (i=0; i < (MagickOffsetType) length; i+=count)
540 #if !defined(MAGICKCORE_HAVE_PREAD)
541 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
542 (MagickSizeType) SSIZE_MAX));
544 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
545 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
556 #if !defined(MAGICKCORE_HAVE_PREAD)
557 UnlockSemaphoreInfo(cache_info->disk_semaphore);
562 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
563 const MagickOffsetType offset,const MagickSizeType length,
564 const unsigned char *restrict buffer)
566 register MagickOffsetType
572 cache_info->timestamp=time(0);
573 #if !defined(MAGICKCORE_HAVE_PWRITE)
574 LockSemaphoreInfo(cache_info->disk_semaphore);
575 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
577 UnlockSemaphoreInfo(cache_info->disk_semaphore);
578 return((MagickOffsetType) -1);
582 for (i=0; i < (MagickOffsetType) length; i+=count)
584 #if !defined(MAGICKCORE_HAVE_PWRITE)
585 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
586 (MagickSizeType) SSIZE_MAX));
588 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
589 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
600 #if !defined(MAGICKCORE_HAVE_PWRITE)
601 UnlockSemaphoreInfo(cache_info->disk_semaphore);
606 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
607 CacheInfo *cache_info,ExceptionInfo *exception)
612 register MagickOffsetType
622 Clone pixel cache (both caches on disk).
624 if (cache_info->debug != MagickFalse)
625 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
626 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
628 if (blob == (unsigned char *) NULL)
630 (void) ThrowMagickException(exception,GetMagickModule(),
631 ResourceLimitError,"MemoryAllocationFailed","`%s'",
632 cache_info->filename);
635 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
637 blob=(unsigned char *) RelinquishMagickMemory(blob);
638 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
639 cache_info->cache_filename);
642 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
644 (void) ClosePixelCacheOnDisk(cache_info);
645 blob=(unsigned char *) RelinquishMagickMemory(blob);
646 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
647 clone_info->cache_filename);
651 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
653 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
654 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
658 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
659 cache_info->cache_filename);
662 length=(size_t) count;
663 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
664 if ((MagickSizeType) count != length)
666 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
667 clone_info->cache_filename);
671 (void) ClosePixelCacheOnDisk(clone_info);
672 (void) ClosePixelCacheOnDisk(cache_info);
673 blob=(unsigned char *) RelinquishMagickMemory(blob);
674 if (i < (MagickOffsetType) cache_info->length)
679 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
680 CacheInfo *cache_info,ExceptionInfo *exception)
685 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
688 Clone pixel cache (both caches in memory).
690 if (cache_info->debug != MagickFalse)
691 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
692 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
696 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
699 Clone pixel cache (one cache on disk, one in memory).
701 if (cache_info->debug != MagickFalse)
702 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
703 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
705 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
706 cache_info->cache_filename);
709 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
710 cache_info->length,(unsigned char *) clone_info->pixels);
711 (void) ClosePixelCacheOnDisk(cache_info);
712 if ((MagickSizeType) count != cache_info->length)
714 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
715 cache_info->cache_filename);
720 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
723 Clone pixel cache (one cache on disk, one in memory).
725 if (clone_info->debug != MagickFalse)
726 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
727 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
729 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
730 clone_info->cache_filename);
733 count=WritePixelCacheRegion(clone_info,clone_info->offset,
734 clone_info->length,(unsigned char *) cache_info->pixels);
735 (void) ClosePixelCacheOnDisk(clone_info);
736 if ((MagickSizeType) count != clone_info->length)
738 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
739 clone_info->cache_filename);
745 Clone pixel cache (both caches on disk).
747 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
750 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
751 CacheInfo *cache_info,ExceptionInfo *exception)
764 register unsigned char
777 Clone pixel cache (unoptimized).
779 if (cache_info->debug != MagickFalse)
781 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
782 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
784 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
787 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
790 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
793 clone_info->number_channels)*sizeof(Quantum),MagickMax(
794 cache_info->metacontent_extent,clone_info->metacontent_extent));
795 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
796 if (blob == (unsigned char *) NULL)
798 (void) ThrowMagickException(exception,GetMagickModule(),
799 ResourceLimitError,"MemoryAllocationFailed","`%s'",
800 cache_info->filename);
803 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
806 if (cache_info->type == DiskCache)
808 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
810 blob=(unsigned char *) RelinquishMagickMemory(blob);
811 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
812 cache_info->cache_filename);
815 cache_offset=cache_info->offset;
817 if (clone_info->type == DiskCache)
819 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
821 blob=(unsigned char *) RelinquishMagickMemory(blob);
822 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
823 clone_info->cache_filename);
826 clone_offset=clone_info->offset;
829 Clone pixel channels.
833 for (y=0; y < (ssize_t) cache_info->rows; y++)
835 for (x=0; x < (ssize_t) cache_info->columns; x++)
841 Read a set of pixel channels.
843 length=cache_info->number_channels*sizeof(Quantum);
844 if (cache_info->type != DiskCache)
845 p=(unsigned char *) cache_info->pixels+cache_offset;
848 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
849 if ((MagickSizeType) count != length)
855 cache_offset+=length;
856 if ((y < (ssize_t) clone_info->rows) &&
857 (x < (ssize_t) clone_info->columns))
858 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
870 Write a set of pixel channels.
872 channel=clone_info->channel_map[i].channel;
873 traits=cache_info->channel_map[channel].traits;
874 if (traits == UndefinedPixelTrait)
876 clone_offset+=sizeof(Quantum);
879 offset=cache_info->channel_map[channel].offset;
880 if (clone_info->type != DiskCache)
881 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
882 offset*sizeof(Quantum),sizeof(Quantum));
885 count=WritePixelCacheRegion(clone_info,clone_offset,
886 sizeof(Quantum),p+offset*sizeof(Quantum));
887 if ((MagickSizeType) count != sizeof(Quantum))
893 clone_offset+=sizeof(Quantum);
896 length=clone_info->number_channels*sizeof(Quantum);
897 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
898 for ( ; x < (ssize_t) clone_info->columns; x++)
901 Set remaining columns as undefined.
903 if (clone_info->type != DiskCache)
904 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
908 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
909 if ((MagickSizeType) count != length)
915 clone_offset+=length;
918 length=clone_info->number_channels*sizeof(Quantum);
919 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
920 for ( ; y < (ssize_t) clone_info->rows; y++)
923 Set remaining rows as undefined.
925 for (x=0; x < (ssize_t) clone_info->columns; x++)
927 if (clone_info->type != DiskCache)
928 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
932 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
933 if ((MagickSizeType) count != length)
939 clone_offset+=length;
942 if ((cache_info->metacontent_extent != 0) ||
943 (clone_info->metacontent_extent != 0))
948 for (y=0; y < (ssize_t) cache_info->rows; y++)
950 for (x=0; x < (ssize_t) cache_info->columns; x++)
953 Read a set of metacontent.
955 length=cache_info->metacontent_extent;
956 if (cache_info->type != DiskCache)
957 p=(unsigned char *) cache_info->pixels+cache_offset;
960 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
961 if ((MagickSizeType) count != length)
967 cache_offset+=length;
968 if ((y < (ssize_t) clone_info->rows) &&
969 (x < (ssize_t) clone_info->columns))
972 Write a set of metacontent.
974 length=clone_info->metacontent_extent;
975 if (clone_info->type != DiskCache)
976 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
980 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
981 if ((MagickSizeType) count != length)
987 clone_offset+=length;
990 length=clone_info->metacontent_extent;
991 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
992 for ( ; x < (ssize_t) clone_info->columns; x++)
995 Set remaining columns as undefined.
997 if (clone_info->type != DiskCache)
998 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1002 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1003 if ((MagickSizeType) count != length)
1009 clone_offset+=length;
1012 length=clone_info->metacontent_extent;
1013 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1014 for ( ; y < (ssize_t) clone_info->rows; y++)
1017 Set remaining rows as undefined.
1019 for (x=0; x < (ssize_t) clone_info->columns; x++)
1021 if (clone_info->type != DiskCache)
1022 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1026 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1027 if ((MagickSizeType) count != length)
1033 clone_offset+=length;
1037 if (clone_info->type == DiskCache)
1038 (void) ClosePixelCacheOnDisk(clone_info);
1039 if (cache_info->type == DiskCache)
1040 (void) ClosePixelCacheOnDisk(cache_info);
1041 blob=(unsigned char *) RelinquishMagickMemory(blob);
1045 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1046 CacheInfo *cache_info,ExceptionInfo *exception)
1052 if (cache_info->type == PingCache)
1054 p=cache_info->channel_map;
1055 q=clone_info->channel_map;
1056 if ((cache_info->columns == clone_info->columns) &&
1057 (cache_info->rows == clone_info->rows) &&
1058 (cache_info->number_channels == clone_info->number_channels) &&
1059 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1060 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1061 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1062 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1066 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1070 + C l o n e P i x e l C a c h e M e t h o d s %
1074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1076 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1079 % The format of the ClonePixelCacheMethods() method is:
1081 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1083 % A description of each parameter follows:
1085 % o clone: Specifies a pointer to a Cache structure.
1087 % o cache: the pixel cache.
1090 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1096 assert(clone != (Cache) NULL);
1097 source_info=(CacheInfo *) clone;
1098 assert(source_info->signature == MagickSignature);
1099 if (source_info->debug != MagickFalse)
1100 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1101 source_info->filename);
1102 assert(cache != (Cache) NULL);
1103 cache_info=(CacheInfo *) cache;
1104 assert(cache_info->signature == MagickSignature);
1105 source_info->methods=cache_info->methods;
1109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1113 + D e s t r o y I m a g e P i x e l C a c h e %
1117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1121 % The format of the DestroyImagePixelCache() method is:
1123 % void DestroyImagePixelCache(Image *image)
1125 % A description of each parameter follows:
1127 % o image: the image.
1130 static void DestroyImagePixelCache(Image *image)
1132 assert(image != (Image *) NULL);
1133 assert(image->signature == MagickSignature);
1134 if (image->debug != MagickFalse)
1135 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1136 if (image->cache == (void *) NULL)
1138 image->cache=DestroyPixelCache(image->cache);
1142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1146 + D e s t r o y I m a g e P i x e l s %
1150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1154 % The format of the DestroyImagePixels() method is:
1156 % void DestroyImagePixels(Image *image)
1158 % A description of each parameter follows:
1160 % o image: the image.
1163 MagickExport void DestroyImagePixels(Image *image)
1168 assert(image != (const Image *) NULL);
1169 assert(image->signature == MagickSignature);
1170 if (image->debug != MagickFalse)
1171 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1172 assert(image->cache != (Cache) NULL);
1173 cache_info=(CacheInfo *) image->cache;
1174 assert(cache_info->signature == MagickSignature);
1175 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1177 cache_info->methods.destroy_pixel_handler(image);
1180 image->cache=DestroyPixelCache(image->cache);
1184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1188 + D e s t r o y P i x e l C a c h e %
1192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1194 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1196 % The format of the DestroyPixelCache() method is:
1198 % Cache DestroyPixelCache(Cache cache)
1200 % A description of each parameter follows:
1202 % o cache: the pixel cache.
1206 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1208 switch (cache_info->type)
1212 if (cache_info->mapped == MagickFalse)
1213 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
1214 cache_info->pixels);
1216 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1217 (size_t) cache_info->length);
1218 RelinquishMagickResource(MemoryResource,cache_info->length);
1223 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1224 cache_info->length);
1225 RelinquishMagickResource(MapResource,cache_info->length);
1229 if (cache_info->file != -1)
1230 (void) ClosePixelCacheOnDisk(cache_info);
1231 RelinquishMagickResource(DiskResource,cache_info->length);
1237 cache_info->type=UndefinedCache;
1238 cache_info->mapped=MagickFalse;
1239 cache_info->metacontent=(void *) NULL;
1242 MagickPrivate Cache DestroyPixelCache(Cache cache)
1247 assert(cache != (Cache) NULL);
1248 cache_info=(CacheInfo *) cache;
1249 assert(cache_info->signature == MagickSignature);
1250 if (cache_info->debug != MagickFalse)
1251 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1252 cache_info->filename);
1253 LockSemaphoreInfo(cache_info->semaphore);
1254 cache_info->reference_count--;
1255 if (cache_info->reference_count != 0)
1257 UnlockSemaphoreInfo(cache_info->semaphore);
1258 return((Cache) NULL);
1260 UnlockSemaphoreInfo(cache_info->semaphore);
1261 if (cache_info->debug != MagickFalse)
1264 message[MaxTextExtent];
1266 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1267 cache_info->filename);
1268 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1270 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1271 (cache_info->type != DiskCache)))
1272 RelinquishPixelCachePixels(cache_info);
1275 RelinquishPixelCachePixels(cache_info);
1276 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1278 *cache_info->cache_filename='\0';
1279 if (cache_info->nexus_info != (NexusInfo **) NULL)
1280 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1281 cache_info->number_threads);
1282 if (cache_info->random_info != (RandomInfo *) NULL)
1283 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1284 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1285 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1286 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1287 DestroySemaphoreInfo(&cache_info->semaphore);
1288 cache_info->signature=(~MagickSignature);
1289 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1299 + D e s t r o y P i x e l C a c h e N e x u s %
1303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1307 % The format of the DestroyPixelCacheNexus() method is:
1309 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1310 % const size_t number_threads)
1312 % A description of each parameter follows:
1314 % o nexus_info: the nexus to destroy.
1316 % o number_threads: the number of nexus threads.
1320 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1322 if (nexus_info->mapped == MagickFalse)
1323 (void) RelinquishAlignedMemory(nexus_info->cache);
1325 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1326 nexus_info->cache=(Quantum *) NULL;
1327 nexus_info->pixels=(Quantum *) NULL;
1328 nexus_info->metacontent=(void *) NULL;
1329 nexus_info->length=0;
1330 nexus_info->mapped=MagickFalse;
1333 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1334 const size_t number_threads)
1339 assert(nexus_info != (NexusInfo **) NULL);
1340 for (i=0; i < (ssize_t) number_threads; i++)
1342 if (nexus_info[i]->cache != (Quantum *) NULL)
1343 RelinquishCacheNexusPixels(nexus_info[i]);
1344 nexus_info[i]->signature=(~MagickSignature);
1346 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1347 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1356 % G e t A u t h e n t i c M e t a c o n t e n t %
1360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1362 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1363 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1364 % returned if the associated pixels are not available.
1366 % The format of the GetAuthenticMetacontent() method is:
1368 % void *GetAuthenticMetacontent(const Image *image)
1370 % A description of each parameter follows:
1372 % o image: the image.
1375 MagickExport void *GetAuthenticMetacontent(const Image *image)
1381 id = GetOpenMPThreadId();
1386 assert(image != (const Image *) NULL);
1387 assert(image->signature == MagickSignature);
1388 assert(image->cache != (Cache) NULL);
1389 cache_info=(CacheInfo *) image->cache;
1390 assert(cache_info->signature == MagickSignature);
1391 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1392 (GetAuthenticMetacontentFromHandler) NULL)
1394 metacontent=cache_info->methods.
1395 get_authentic_metacontent_from_handler(image);
1396 return(metacontent);
1398 assert(id < (int) cache_info->number_threads);
1399 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1400 cache_info->nexus_info[id]);
1401 return(metacontent);
1405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409 + 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 %
1413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1415 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1416 % with the last call to QueueAuthenticPixelsCache() or
1417 % GetAuthenticPixelsCache().
1419 % The format of the GetAuthenticMetacontentFromCache() method is:
1421 % void *GetAuthenticMetacontentFromCache(const Image *image)
1423 % A description of each parameter follows:
1425 % o image: the image.
1428 static void *GetAuthenticMetacontentFromCache(const Image *image)
1434 id = GetOpenMPThreadId();
1439 assert(image != (const Image *) NULL);
1440 assert(image->signature == MagickSignature);
1441 assert(image->cache != (Cache) NULL);
1442 cache_info=(CacheInfo *) image->cache;
1443 assert(cache_info->signature == MagickSignature);
1444 assert(id < (int) cache_info->number_threads);
1445 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1446 cache_info->nexus_info[id]);
1447 return(metacontent);
1451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1455 + 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 %
1459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1461 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1462 % disk pixel cache as defined by the geometry parameters. A pointer to the
1463 % pixels is returned if the pixels are transferred, otherwise a NULL is
1466 % The format of the GetAuthenticPixelCacheNexus() method is:
1468 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1469 % const ssize_t y,const size_t columns,const size_t rows,
1470 % NexusInfo *nexus_info,ExceptionInfo *exception)
1472 % A description of each parameter follows:
1474 % o image: the image.
1476 % o x,y,columns,rows: These values define the perimeter of a region of
1479 % o nexus_info: the cache nexus to return.
1481 % o exception: return any errors or warnings in this structure.
1485 static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
1486 NexusInfo *nexus_info)
1494 if (cache_info->type == PingCache)
1496 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1497 nexus_info->region.x;
1498 status=nexus_info->pixels == (cache_info->pixels+offset*
1499 cache_info->number_channels) ? MagickTrue : MagickFalse;
1503 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1504 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1505 NexusInfo *nexus_info,ExceptionInfo *exception)
1514 Transfer pixels from the cache.
1516 assert(image != (Image *) NULL);
1517 assert(image->signature == MagickSignature);
1518 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1520 if (q == (Quantum *) NULL)
1521 return((Quantum *) NULL);
1522 cache_info=(CacheInfo *) image->cache;
1523 assert(cache_info->signature == MagickSignature);
1524 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1526 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1527 return((Quantum *) NULL);
1528 if (cache_info->metacontent_extent != 0)
1529 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1530 return((Quantum *) NULL);
1535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1539 + 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 %
1543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1545 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1546 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1548 % The format of the GetAuthenticPixelsFromCache() method is:
1550 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1552 % A description of each parameter follows:
1554 % o image: the image.
1557 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1563 id = GetOpenMPThreadId();
1565 assert(image != (const Image *) NULL);
1566 assert(image->signature == MagickSignature);
1567 assert(image->cache != (Cache) NULL);
1568 cache_info=(CacheInfo *) image->cache;
1569 assert(cache_info->signature == MagickSignature);
1570 assert(id < (int) cache_info->number_threads);
1571 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1579 % G e t A u t h e n t i c P i x e l Q u e u e %
1583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1585 % GetAuthenticPixelQueue() returns the authentic pixels associated
1586 % corresponding with the last call to QueueAuthenticPixels() or
1587 % GetAuthenticPixels().
1589 % The format of the GetAuthenticPixelQueue() method is:
1591 % Quantum *GetAuthenticPixelQueue(const Image image)
1593 % A description of each parameter follows:
1595 % o image: the image.
1598 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1604 id = GetOpenMPThreadId();
1606 assert(image != (const Image *) NULL);
1607 assert(image->signature == MagickSignature);
1608 assert(image->cache != (Cache) NULL);
1609 cache_info=(CacheInfo *) image->cache;
1610 assert(cache_info->signature == MagickSignature);
1611 if (cache_info->methods.get_authentic_pixels_from_handler !=
1612 (GetAuthenticPixelsFromHandler) NULL)
1613 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1614 assert(id < (int) cache_info->number_threads);
1615 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623 % G e t A u t h e n t i c P i x e l s %
1626 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1628 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1629 % region is successfully accessed, a pointer to a Quantum array
1630 % representing the region is returned, otherwise NULL is returned.
1632 % The returned pointer may point to a temporary working copy of the pixels
1633 % or it may point to the original pixels in memory. Performance is maximized
1634 % if the selected region is part of one row, or one or more full rows, since
1635 % then there is opportunity to access the pixels in-place (without a copy)
1636 % if the image is in memory, or in a memory-mapped file. The returned pointer
1637 % must *never* be deallocated by the user.
1639 % Pixels accessed via the returned pointer represent a simple array of type
1640 % Quantum. If the image has corresponding metacontent,call
1641 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1642 % meta-content corresponding to the region. Once the Quantum array has
1643 % been updated, the changes must be saved back to the underlying image using
1644 % SyncAuthenticPixels() or they may be lost.
1646 % The format of the GetAuthenticPixels() method is:
1648 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1649 % const ssize_t y,const size_t columns,const size_t rows,
1650 % ExceptionInfo *exception)
1652 % A description of each parameter follows:
1654 % o image: the image.
1656 % o x,y,columns,rows: These values define the perimeter of a region of
1659 % o exception: return any errors or warnings in this structure.
1662 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1663 const ssize_t y,const size_t columns,const size_t rows,
1664 ExceptionInfo *exception)
1670 id = GetOpenMPThreadId();
1675 assert(image != (Image *) NULL);
1676 assert(image->signature == MagickSignature);
1677 assert(image->cache != (Cache) NULL);
1678 cache_info=(CacheInfo *) image->cache;
1679 assert(cache_info->signature == MagickSignature);
1680 if (cache_info->methods.get_authentic_pixels_handler !=
1681 (GetAuthenticPixelsHandler) NULL)
1683 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1687 assert(id < (int) cache_info->number_threads);
1688 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1689 cache_info->nexus_info[id],exception);
1694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1698 + G e t A u t h e n t i c P i x e l s C a c h e %
1702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1704 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1705 % as defined by the geometry parameters. A pointer to the pixels is returned
1706 % if the pixels are transferred, otherwise a NULL is returned.
1708 % The format of the GetAuthenticPixelsCache() method is:
1710 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1711 % const ssize_t y,const size_t columns,const size_t rows,
1712 % ExceptionInfo *exception)
1714 % A description of each parameter follows:
1716 % o image: the image.
1718 % o x,y,columns,rows: These values define the perimeter of a region of
1721 % o exception: return any errors or warnings in this structure.
1724 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1725 const ssize_t y,const size_t columns,const size_t rows,
1726 ExceptionInfo *exception)
1732 id = GetOpenMPThreadId();
1737 assert(image != (const Image *) NULL);
1738 assert(image->signature == MagickSignature);
1739 assert(image->cache != (Cache) NULL);
1740 cache_info=(CacheInfo *) image->cache;
1741 if (cache_info == (Cache) NULL)
1742 return((Quantum *) NULL);
1743 assert(cache_info->signature == MagickSignature);
1744 assert(id < (int) cache_info->number_threads);
1745 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1746 cache_info->nexus_info[id],exception);
1751 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1755 + G e t I m a g e E x t e n t %
1759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1761 % GetImageExtent() returns the extent of the pixels associated corresponding
1762 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1764 % The format of the GetImageExtent() method is:
1766 % MagickSizeType GetImageExtent(const Image *image)
1768 % A description of each parameter follows:
1770 % o image: the image.
1773 MagickExport MagickSizeType GetImageExtent(const Image *image)
1779 id = GetOpenMPThreadId();
1781 assert(image != (Image *) NULL);
1782 assert(image->signature == MagickSignature);
1783 if (image->debug != MagickFalse)
1784 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1785 assert(image->cache != (Cache) NULL);
1786 cache_info=(CacheInfo *) image->cache;
1787 assert(cache_info->signature == MagickSignature);
1788 assert(id < (int) cache_info->number_threads);
1789 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1797 + G e t I m a g e P i x e l C a c h e %
1801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1803 % GetImagePixelCache() ensures that there is only a single reference to the
1804 % pixel cache to be modified, updating the provided cache pointer to point to
1805 % a clone of the original pixel cache if necessary.
1807 % The format of the GetImagePixelCache method is:
1809 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1810 % ExceptionInfo *exception)
1812 % A description of each parameter follows:
1814 % o image: the image.
1816 % o clone: any value other than MagickFalse clones the cache pixels.
1818 % o exception: return any errors or warnings in this structure.
1822 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1832 Does the image match the pixel cache morphology?
1834 cache_info=(CacheInfo *) image->cache;
1835 p=image->channel_map;
1836 q=cache_info->channel_map;
1837 if ((image->storage_class != cache_info->storage_class) ||
1838 (image->colorspace != cache_info->colorspace) ||
1839 (image->matte != cache_info->matte) ||
1840 (image->mask != cache_info->mask) ||
1841 (image->columns != cache_info->columns) ||
1842 (image->rows != cache_info->rows) ||
1843 (image->number_channels != cache_info->number_channels) ||
1844 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1845 (image->metacontent_extent != cache_info->metacontent_extent) ||
1846 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1847 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1848 return(MagickFalse);
1852 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1853 ExceptionInfo *exception)
1862 static MagickSizeType
1868 cache_timestamp = 0;
1871 LockSemaphoreInfo(image->semaphore);
1872 if (cpu_throttle == 0)
1878 Set CPU throttle in milleseconds.
1880 cpu_throttle=MagickResourceInfinity;
1881 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1882 if (limit == (char *) NULL)
1883 limit=GetPolicyValue("throttle");
1884 if (limit != (char *) NULL)
1886 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1887 limit=DestroyString(limit);
1890 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1891 MagickDelay(cpu_throttle);
1892 if (time_limit == 0)
1895 Set the exire time in seconds.
1897 time_limit=GetMagickResourceLimit(TimeResource);
1898 cache_timestamp=time((time_t *) NULL);
1900 if ((time_limit != MagickResourceInfinity) &&
1901 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1902 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1903 assert(image->cache != (Cache) NULL);
1904 cache_info=(CacheInfo *) image->cache;
1905 destroy=MagickFalse;
1906 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1908 LockSemaphoreInfo(cache_info->semaphore);
1909 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1920 clone_image=(*image);
1921 clone_image.semaphore=AllocateSemaphoreInfo();
1922 clone_image.reference_count=1;
1923 clone_image.cache=ClonePixelCache(cache_info);
1924 clone_info=(CacheInfo *) clone_image.cache;
1925 status=OpenPixelCache(&clone_image,IOMode,exception);
1926 if (status != MagickFalse)
1928 if (clone != MagickFalse)
1929 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1930 if (status != MagickFalse)
1932 if (cache_info->mode == ReadMode)
1933 cache_info->nexus_info=(NexusInfo **) NULL;
1935 image->cache=clone_image.cache;
1938 DestroySemaphoreInfo(&clone_image.semaphore);
1940 UnlockSemaphoreInfo(cache_info->semaphore);
1942 if (destroy != MagickFalse)
1943 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1944 if (status != MagickFalse)
1947 Ensure the image matches the pixel cache morphology.
1949 image->taint=MagickTrue;
1950 image->type=UndefinedType;
1951 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1953 status=OpenPixelCache(image,IOMode,exception);
1954 cache_info=(CacheInfo *) image->cache;
1955 if (cache_info->type == DiskCache)
1956 (void) ClosePixelCacheOnDisk(cache_info);
1959 UnlockSemaphoreInfo(image->semaphore);
1960 if (status == MagickFalse)
1961 return((Cache) NULL);
1962 return(image->cache);
1966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1970 % G e t O n e A u t h e n t i c P i x e l %
1974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1976 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
1977 % location. The image background color is returned if an error occurs.
1979 % The format of the GetOneAuthenticPixel() method is:
1981 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
1982 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
1984 % A description of each parameter follows:
1986 % o image: the image.
1988 % o x,y: These values define the location of the pixel to return.
1990 % o pixel: return a pixel at the specified (x,y) location.
1992 % o exception: return any errors or warnings in this structure.
1995 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
1996 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2007 assert(image != (Image *) NULL);
2008 assert(image->signature == MagickSignature);
2009 assert(image->cache != (Cache) NULL);
2010 cache_info=(CacheInfo *) image->cache;
2011 assert(cache_info->signature == MagickSignature);
2012 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2013 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2014 (GetOneAuthenticPixelFromHandler) NULL)
2015 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2017 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2018 if (q == (Quantum *) NULL)
2020 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2021 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2022 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2023 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2024 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2025 return(MagickFalse);
2027 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2032 channel=GetPixelChannelMapChannel(image,i);
2033 pixel[channel]=q[i];
2039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2043 + 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 %
2047 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2049 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2050 % location. The image background color is returned if an error occurs.
2052 % The format of the GetOneAuthenticPixelFromCache() method is:
2054 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2055 % const ssize_t x,const ssize_t y,Quantum *pixel,
2056 % ExceptionInfo *exception)
2058 % A description of each parameter follows:
2060 % o image: the image.
2062 % o x,y: These values define the location of the pixel to return.
2064 % o pixel: return a pixel at the specified (x,y) location.
2066 % o exception: return any errors or warnings in this structure.
2069 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2070 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2076 id = GetOpenMPThreadId();
2084 assert(image != (const Image *) NULL);
2085 assert(image->signature == MagickSignature);
2086 assert(image->cache != (Cache) NULL);
2087 cache_info=(CacheInfo *) image->cache;
2088 assert(cache_info->signature == MagickSignature);
2089 assert(id < (int) cache_info->number_threads);
2090 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2091 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2093 if (q == (Quantum *) NULL)
2095 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2096 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2097 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2098 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2099 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2100 return(MagickFalse);
2102 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2107 channel=GetPixelChannelMapChannel(image,i);
2108 pixel[channel]=q[i];
2114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2118 % G e t O n e V i r t u a l P i x e l %
2122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2124 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2125 % (x,y) location. The image background color is returned if an error occurs.
2126 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2128 % The format of the GetOneVirtualPixel() method is:
2130 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2131 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2133 % A description of each parameter follows:
2135 % o image: the image.
2137 % o x,y: These values define the location of the pixel to return.
2139 % o pixel: return a pixel at the specified (x,y) location.
2141 % o exception: return any errors or warnings in this structure.
2144 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2145 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2151 id = GetOpenMPThreadId();
2159 assert(image != (const Image *) NULL);
2160 assert(image->signature == MagickSignature);
2161 assert(image->cache != (Cache) NULL);
2162 cache_info=(CacheInfo *) image->cache;
2163 assert(cache_info->signature == MagickSignature);
2164 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2165 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2166 (GetOneVirtualPixelFromHandler) NULL)
2167 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2168 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2169 assert(id < (int) cache_info->number_threads);
2170 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2171 1UL,1UL,cache_info->nexus_info[id],exception);
2172 if (p == (const Quantum *) NULL)
2174 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2175 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2176 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2177 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2178 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2179 return(MagickFalse);
2181 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2186 channel=GetPixelChannelMapChannel(image,i);
2187 pixel[channel]=p[i];
2193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2197 + 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 %
2201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2203 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2204 % specified (x,y) location. The image background color is returned if an
2207 % The format of the GetOneVirtualPixelFromCache() method is:
2209 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2210 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2211 % Quantum *pixel,ExceptionInfo *exception)
2213 % A description of each parameter follows:
2215 % o image: the image.
2217 % o virtual_pixel_method: the virtual pixel method.
2219 % o x,y: These values define the location of the pixel to return.
2221 % o pixel: return a pixel at the specified (x,y) location.
2223 % o exception: return any errors or warnings in this structure.
2226 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2227 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2228 Quantum *pixel,ExceptionInfo *exception)
2234 id = GetOpenMPThreadId();
2242 assert(image != (const Image *) NULL);
2243 assert(image->signature == MagickSignature);
2244 assert(image->cache != (Cache) NULL);
2245 cache_info=(CacheInfo *) image->cache;
2246 assert(cache_info->signature == MagickSignature);
2247 assert(id < (int) cache_info->number_threads);
2248 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2249 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2250 cache_info->nexus_info[id],exception);
2251 if (p == (const Quantum *) NULL)
2253 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2254 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2255 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2256 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2257 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2258 return(MagickFalse);
2260 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2265 channel=GetPixelChannelMapChannel(image,i);
2266 pixel[channel]=p[i];
2272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2276 % G e t O n e V i r t u a l P i x e l I n f o %
2280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2282 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2283 % location. The image background color is returned if an error occurs. If
2284 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2286 % The format of the GetOneVirtualPixelInfo() method is:
2288 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2289 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2290 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2292 % A description of each parameter follows:
2294 % o image: the image.
2296 % o virtual_pixel_method: the virtual pixel method.
2298 % o x,y: these values define the location of the pixel to return.
2300 % o pixel: return a pixel at the specified (x,y) location.
2302 % o exception: return any errors or warnings in this structure.
2305 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2306 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2307 PixelInfo *pixel,ExceptionInfo *exception)
2313 id = GetOpenMPThreadId();
2315 register const Quantum
2318 assert(image != (const Image *) NULL);
2319 assert(image->signature == MagickSignature);
2320 assert(image->cache != (Cache) NULL);
2321 cache_info=(CacheInfo *) image->cache;
2322 assert(cache_info->signature == MagickSignature);
2323 assert(id < (int) cache_info->number_threads);
2324 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2325 cache_info->nexus_info[id],exception);
2326 GetPixelInfo(image,pixel);
2327 if (p == (const Quantum *) NULL)
2328 return(MagickFalse);
2329 GetPixelInfoPixel(image,p,pixel);
2334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2338 + G e t P i x e l C a c h e C o l o r s p a c e %
2342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2344 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2346 % The format of the GetPixelCacheColorspace() method is:
2348 % Colorspace GetPixelCacheColorspace(Cache cache)
2350 % A description of each parameter follows:
2352 % o cache: the pixel cache.
2355 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2360 assert(cache != (Cache) NULL);
2361 cache_info=(CacheInfo *) cache;
2362 assert(cache_info->signature == MagickSignature);
2363 if (cache_info->debug != MagickFalse)
2364 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2365 cache_info->filename);
2366 return(cache_info->colorspace);
2370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2374 + G e t P i x e l C a c h e M e t h o d s %
2378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2380 % GetPixelCacheMethods() initializes the CacheMethods structure.
2382 % The format of the GetPixelCacheMethods() method is:
2384 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2386 % A description of each parameter follows:
2388 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2391 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2393 assert(cache_methods != (CacheMethods *) NULL);
2394 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2395 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2396 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2397 cache_methods->get_virtual_metacontent_from_handler=
2398 GetVirtualMetacontentFromCache;
2399 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2400 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2401 cache_methods->get_authentic_metacontent_from_handler=
2402 GetAuthenticMetacontentFromCache;
2403 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2404 cache_methods->get_one_authentic_pixel_from_handler=
2405 GetOneAuthenticPixelFromCache;
2406 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2407 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2408 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2416 + G e t P i x e l C a c h e N e x u s E x t e n t %
2420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2422 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2423 % corresponding with the last call to SetPixelCacheNexusPixels() or
2424 % GetPixelCacheNexusPixels().
2426 % The format of the GetPixelCacheNexusExtent() method is:
2428 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2429 % NexusInfo *nexus_info)
2431 % A description of each parameter follows:
2433 % o nexus_info: the nexus info.
2436 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2437 NexusInfo *nexus_info)
2445 assert(cache != NULL);
2446 cache_info=(CacheInfo *) cache;
2447 assert(cache_info->signature == MagickSignature);
2448 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2450 return((MagickSizeType) cache_info->columns*cache_info->rows);
2455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2459 + 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 %
2463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2468 % The format of the GetPixelCacheNexusMetacontent() method is:
2470 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2471 % NexusInfo *nexus_info)
2473 % A description of each parameter follows:
2475 % o cache: the pixel cache.
2477 % o nexus_info: the cache nexus to return the meta-content.
2480 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2481 NexusInfo *nexus_info)
2486 assert(cache != NULL);
2487 cache_info=(CacheInfo *) cache;
2488 assert(cache_info->signature == MagickSignature);
2489 if (cache_info->storage_class == UndefinedClass)
2490 return((void *) NULL);
2491 return(nexus_info->metacontent);
2495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2499 + G e t P i x e l C a c h e N e x u s P i x e l s %
2503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2505 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2508 % The format of the GetPixelCacheNexusPixels() method is:
2510 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2511 % NexusInfo *nexus_info)
2513 % A description of each parameter follows:
2515 % o cache: the pixel cache.
2517 % o nexus_info: the cache nexus to return the pixels.
2520 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2521 NexusInfo *nexus_info)
2526 assert(cache != NULL);
2527 cache_info=(CacheInfo *) cache;
2528 assert(cache_info->signature == MagickSignature);
2529 if (cache_info->storage_class == UndefinedClass)
2530 return((Quantum *) NULL);
2531 return(nexus_info->pixels);
2535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2539 + G e t P i x e l C a c h e P i x e l s %
2543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2545 % GetPixelCachePixels() returns the pixels associated with the specified image.
2547 % The format of the GetPixelCachePixels() method is:
2549 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2550 % ExceptionInfo *exception)
2552 % A description of each parameter follows:
2554 % o image: the image.
2556 % o length: the pixel cache length.
2558 % o exception: return any errors or warnings in this structure.
2561 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2562 ExceptionInfo *exception)
2567 assert(image != (const Image *) NULL);
2568 assert(image->signature == MagickSignature);
2569 assert(image->cache != (Cache) NULL);
2570 assert(length != (MagickSizeType *) NULL);
2571 assert(exception != (ExceptionInfo *) NULL);
2572 assert(exception->signature == MagickSignature);
2573 cache_info=(CacheInfo *) image->cache;
2574 assert(cache_info->signature == MagickSignature);
2576 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2577 return((void *) NULL);
2578 *length=cache_info->length;
2579 return((void *) cache_info->pixels);
2583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2587 + 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 %
2591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2593 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2595 % The format of the GetPixelCacheStorageClass() method is:
2597 % ClassType GetPixelCacheStorageClass(Cache cache)
2599 % A description of each parameter follows:
2601 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2603 % o cache: the pixel cache.
2606 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2611 assert(cache != (Cache) NULL);
2612 cache_info=(CacheInfo *) cache;
2613 assert(cache_info->signature == MagickSignature);
2614 if (cache_info->debug != MagickFalse)
2615 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2616 cache_info->filename);
2617 return(cache_info->storage_class);
2621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2625 + G e t P i x e l C a c h e T i l e S i z e %
2629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2631 % GetPixelCacheTileSize() returns the pixel cache tile size.
2633 % The format of the GetPixelCacheTileSize() method is:
2635 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2638 % A description of each parameter follows:
2640 % o image: the image.
2642 % o width: the optimize cache tile width in pixels.
2644 % o height: the optimize cache tile height in pixels.
2647 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2653 assert(image != (Image *) NULL);
2654 assert(image->signature == MagickSignature);
2655 if (image->debug != MagickFalse)
2656 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2657 cache_info=(CacheInfo *) image->cache;
2658 assert(cache_info->signature == MagickSignature);
2659 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2660 if (GetPixelCacheType(image) == DiskCache)
2661 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2670 + G e t P i x e l C a c h e T y p e %
2674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2676 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2678 % The format of the GetPixelCacheType() method is:
2680 % CacheType GetPixelCacheType(const Image *image)
2682 % A description of each parameter follows:
2684 % o image: the image.
2687 MagickPrivate CacheType GetPixelCacheType(const Image *image)
2692 assert(image != (Image *) NULL);
2693 assert(image->signature == MagickSignature);
2694 assert(image->cache != (Cache) NULL);
2695 cache_info=(CacheInfo *) image->cache;
2696 assert(cache_info->signature == MagickSignature);
2697 return(cache_info->type);
2701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2705 + 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 %
2709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2711 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2712 % pixel cache. A virtual pixel is any pixel access that is outside the
2713 % boundaries of the image cache.
2715 % The format of the GetPixelCacheVirtualMethod() method is:
2717 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2719 % A description of each parameter follows:
2721 % o image: the image.
2724 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2729 assert(image != (Image *) NULL);
2730 assert(image->signature == MagickSignature);
2731 assert(image->cache != (Cache) NULL);
2732 cache_info=(CacheInfo *) image->cache;
2733 assert(cache_info->signature == MagickSignature);
2734 return(cache_info->virtual_pixel_method);
2738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2742 + 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 %
2746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2748 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2749 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2751 % The format of the GetVirtualMetacontentFromCache() method is:
2753 % void *GetVirtualMetacontentFromCache(const Image *image)
2755 % A description of each parameter follows:
2757 % o image: the image.
2760 static const void *GetVirtualMetacontentFromCache(const Image *image)
2766 id = GetOpenMPThreadId();
2771 assert(image != (const Image *) NULL);
2772 assert(image->signature == MagickSignature);
2773 assert(image->cache != (Cache) NULL);
2774 cache_info=(CacheInfo *) image->cache;
2775 assert(cache_info->signature == MagickSignature);
2776 assert(id < (int) cache_info->number_threads);
2777 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2778 cache_info->nexus_info[id]);
2779 return(metacontent);
2783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2787 + 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 %
2791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2793 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2796 % The format of the GetVirtualMetacontentFromNexus() method is:
2798 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2799 % NexusInfo *nexus_info)
2801 % A description of each parameter follows:
2803 % o cache: the pixel cache.
2805 % o nexus_info: the cache nexus to return the meta-content.
2808 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2809 NexusInfo *nexus_info)
2814 assert(cache != (Cache) NULL);
2815 cache_info=(CacheInfo *) cache;
2816 assert(cache_info->signature == MagickSignature);
2817 if (cache_info->storage_class == UndefinedClass)
2818 return((void *) NULL);
2819 return(nexus_info->metacontent);
2823 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2827 % G e t V i r t u a l M e t a c o n t e n t %
2831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2833 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2834 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2835 % returned if the meta-content are not available.
2837 % The format of the GetVirtualMetacontent() method is:
2839 % const void *GetVirtualMetacontent(const Image *image)
2841 % A description of each parameter follows:
2843 % o image: the image.
2846 MagickExport const void *GetVirtualMetacontent(const Image *image)
2852 id = GetOpenMPThreadId();
2857 assert(image != (const Image *) NULL);
2858 assert(image->signature == MagickSignature);
2859 assert(image->cache != (Cache) NULL);
2860 cache_info=(CacheInfo *) image->cache;
2861 assert(cache_info->signature == MagickSignature);
2862 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2863 if (metacontent != (GetVirtualMetacontentFromHandler) NULL)
2864 return(metacontent);
2865 assert(id < (int) cache_info->number_threads);
2866 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2867 cache_info->nexus_info[id]);
2868 return(metacontent);
2872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2876 + 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 %
2880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2882 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2883 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2884 % is returned if the pixels are transferred, otherwise a NULL is returned.
2886 % The format of the GetVirtualPixelsFromNexus() method is:
2888 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2889 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2890 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2891 % ExceptionInfo *exception)
2893 % A description of each parameter follows:
2895 % o image: the image.
2897 % o virtual_pixel_method: the virtual pixel method.
2899 % o x,y,columns,rows: These values define the perimeter of a region of
2902 % o nexus_info: the cache nexus to acquire.
2904 % o exception: return any errors or warnings in this structure.
2911 0, 48, 12, 60, 3, 51, 15, 63,
2912 32, 16, 44, 28, 35, 19, 47, 31,
2913 8, 56, 4, 52, 11, 59, 7, 55,
2914 40, 24, 36, 20, 43, 27, 39, 23,
2915 2, 50, 14, 62, 1, 49, 13, 61,
2916 34, 18, 46, 30, 33, 17, 45, 29,
2917 10, 58, 6, 54, 9, 57, 5, 53,
2918 42, 26, 38, 22, 41, 25, 37, 21
2921 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2926 index=x+DitherMatrix[x & 0x07]-32L;
2929 if (index >= (ssize_t) columns)
2930 return((ssize_t) columns-1L);
2934 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2939 index=y+DitherMatrix[y & 0x07]-32L;
2942 if (index >= (ssize_t) rows)
2943 return((ssize_t) rows-1L);
2947 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2951 if (x >= (ssize_t) columns)
2952 return((ssize_t) (columns-1));
2956 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2960 if (y >= (ssize_t) rows)
2961 return((ssize_t) (rows-1));
2965 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2967 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2970 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2972 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2975 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2976 const size_t extent)
2982 Compute the remainder of dividing offset by extent. It returns not only
2983 the quotient (tile the offset falls in) but also the positive remainer
2984 within that tile such that 0 <= remainder < extent. This method is
2985 essentially a ldiv() using a floored modulo division rather than the
2986 normal default truncated modulo division.
2988 modulo.quotient=offset/(ssize_t) extent;
2991 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2995 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
2996 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2997 const size_t columns,const size_t rows,NexusInfo *nexus_info,
2998 ExceptionInfo *exception)
3015 virtual_pixel[CompositePixelChannel];
3020 register const Quantum
3033 register unsigned char
3040 *virtual_metacontent;
3045 assert(image != (const Image *) NULL);
3046 assert(image->signature == MagickSignature);
3047 assert(image->cache != (Cache) NULL);
3048 cache_info=(CacheInfo *) image->cache;
3049 assert(cache_info->signature == MagickSignature);
3050 if (cache_info->type == UndefinedCache)
3051 return((const Quantum *) NULL);
3054 region.width=columns;
3056 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3057 if (pixels == (Quantum *) NULL)
3058 return((const Quantum *) NULL);
3060 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3061 nexus_info->region.x;
3062 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3063 nexus_info->region.width-1L;
3064 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3065 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3066 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3067 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3073 Pixel request is inside cache extents.
3075 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3077 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3078 if (status == MagickFalse)
3079 return((const Quantum *) NULL);
3080 if (cache_info->metacontent_extent != 0)
3082 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3083 if (status == MagickFalse)
3084 return((const Quantum *) NULL);
3089 Pixel request is outside cache extents.
3091 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3092 virtual_nexus=AcquirePixelCacheNexus(1);
3093 if (virtual_nexus == (NexusInfo **) NULL)
3095 if (virtual_nexus != (NexusInfo **) NULL)
3096 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3097 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3098 "UnableToGetCacheNexus","`%s'",image->filename);
3099 return((const Quantum *) NULL);
3101 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3102 sizeof(*virtual_pixel));
3103 virtual_metacontent=(void *) NULL;
3104 switch (virtual_pixel_method)
3106 case BackgroundVirtualPixelMethod:
3107 case BlackVirtualPixelMethod:
3108 case GrayVirtualPixelMethod:
3109 case TransparentVirtualPixelMethod:
3110 case MaskVirtualPixelMethod:
3111 case WhiteVirtualPixelMethod:
3112 case EdgeVirtualPixelMethod:
3113 case CheckerTileVirtualPixelMethod:
3114 case HorizontalTileVirtualPixelMethod:
3115 case VerticalTileVirtualPixelMethod:
3117 if (cache_info->metacontent_extent != 0)
3120 Acquire a metacontent buffer.
3122 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3123 cache_info->metacontent_extent);
3124 if (virtual_metacontent == (void *) NULL)
3126 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3127 (void) ThrowMagickException(exception,GetMagickModule(),
3128 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3129 return((const Quantum *) NULL);
3131 (void) ResetMagickMemory(virtual_metacontent,0,
3132 cache_info->metacontent_extent);
3134 switch (virtual_pixel_method)
3136 case BlackVirtualPixelMethod:
3138 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3139 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3140 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3143 case GrayVirtualPixelMethod:
3145 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3146 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3148 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3151 case TransparentVirtualPixelMethod:
3153 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3154 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3155 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3158 case MaskVirtualPixelMethod:
3159 case WhiteVirtualPixelMethod:
3161 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3162 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3163 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3168 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3170 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3172 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3174 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3176 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3186 for (v=0; v < (ssize_t) rows; v++)
3188 for (u=0; u < (ssize_t) columns; u+=length)
3190 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3191 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3192 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3200 Transfer a single pixel.
3202 length=(MagickSizeType) 1;
3203 switch (virtual_pixel_method)
3207 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3208 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3209 1UL,1UL,*virtual_nexus,exception);
3210 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3213 case RandomVirtualPixelMethod:
3215 if (cache_info->random_info == (RandomInfo *) NULL)
3216 cache_info->random_info=AcquireRandomInfo();
3217 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3218 RandomX(cache_info->random_info,cache_info->columns),
3219 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3220 *virtual_nexus,exception);
3221 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3224 case DitherVirtualPixelMethod:
3226 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3227 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3228 1UL,1UL,*virtual_nexus,exception);
3229 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3232 case TileVirtualPixelMethod:
3234 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3235 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3236 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3237 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3239 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3242 case MirrorVirtualPixelMethod:
3244 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3245 if ((x_modulo.quotient & 0x01) == 1L)
3246 x_modulo.remainder=(ssize_t) cache_info->columns-
3247 x_modulo.remainder-1L;
3248 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3249 if ((y_modulo.quotient & 0x01) == 1L)
3250 y_modulo.remainder=(ssize_t) cache_info->rows-
3251 y_modulo.remainder-1L;
3252 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3253 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3255 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3258 case HorizontalTileEdgeVirtualPixelMethod:
3260 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3261 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3262 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3263 *virtual_nexus,exception);
3264 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3267 case VerticalTileEdgeVirtualPixelMethod:
3269 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3270 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3271 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3272 *virtual_nexus,exception);
3273 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3276 case BackgroundVirtualPixelMethod:
3277 case BlackVirtualPixelMethod:
3278 case GrayVirtualPixelMethod:
3279 case TransparentVirtualPixelMethod:
3280 case MaskVirtualPixelMethod:
3281 case WhiteVirtualPixelMethod:
3284 r=virtual_metacontent;
3287 case EdgeVirtualPixelMethod:
3288 case CheckerTileVirtualPixelMethod:
3290 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3291 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3292 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3295 r=virtual_metacontent;
3298 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3299 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3301 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3304 case HorizontalTileVirtualPixelMethod:
3306 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3309 r=virtual_metacontent;
3312 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3313 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3314 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3315 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3317 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3320 case VerticalTileVirtualPixelMethod:
3322 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3325 r=virtual_metacontent;
3328 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3329 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3330 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3331 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3333 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3337 if (p == (const Quantum *) NULL)
3339 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3341 q+=cache_info->number_channels;
3342 if ((s != (void *) NULL) && (r != (const void *) NULL))
3344 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3345 s+=cache_info->metacontent_extent;
3350 Transfer a run of pixels.
3352 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3353 length,1UL,*virtual_nexus,exception);
3354 if (p == (const Quantum *) NULL)
3356 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3357 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3358 q+=length*cache_info->number_channels;
3359 if ((r != (void *) NULL) && (s != (const void *) NULL))
3361 (void) memcpy(s,r,(size_t) length);
3362 s+=length*cache_info->metacontent_extent;
3369 if (virtual_metacontent != (void *) NULL)
3370 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3371 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3380 + G e t V i r t u a l P i x e l C a c h e %
3384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3386 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3387 % cache as defined by the geometry parameters. A pointer to the pixels
3388 % is returned if the pixels are transferred, otherwise a NULL is returned.
3390 % The format of the GetVirtualPixelCache() method is:
3392 % const Quantum *GetVirtualPixelCache(const Image *image,
3393 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3394 % const ssize_t y,const size_t columns,const size_t rows,
3395 % ExceptionInfo *exception)
3397 % A description of each parameter follows:
3399 % o image: the image.
3401 % o virtual_pixel_method: the virtual pixel method.
3403 % o x,y,columns,rows: These values define the perimeter of a region of
3406 % o exception: return any errors or warnings in this structure.
3409 static const Quantum *GetVirtualPixelCache(const Image *image,
3410 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3411 const size_t columns,const size_t rows,ExceptionInfo *exception)
3417 id = GetOpenMPThreadId();
3422 assert(image != (const Image *) NULL);
3423 assert(image->signature == MagickSignature);
3424 assert(image->cache != (Cache) NULL);
3425 cache_info=(CacheInfo *) image->cache;
3426 assert(cache_info->signature == MagickSignature);
3427 assert(id < (int) cache_info->number_threads);
3428 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3429 cache_info->nexus_info[id],exception);
3434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3438 % G e t V i r t u a l P i x e l Q u e u e %
3442 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3444 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3445 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3447 % The format of the GetVirtualPixelQueue() method is:
3449 % const Quantum *GetVirtualPixelQueue(const Image image)
3451 % A description of each parameter follows:
3453 % o image: the image.
3456 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3462 id = GetOpenMPThreadId();
3464 assert(image != (const Image *) NULL);
3465 assert(image->signature == MagickSignature);
3466 assert(image->cache != (Cache) NULL);
3467 cache_info=(CacheInfo *) image->cache;
3468 assert(cache_info->signature == MagickSignature);
3469 if (cache_info->methods.get_virtual_pixels_handler !=
3470 (GetVirtualPixelsHandler) NULL)
3471 return(cache_info->methods.get_virtual_pixels_handler(image));
3472 assert(id < (int) cache_info->number_threads);
3473 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3481 % G e t V i r t u a l P i x e l s %
3485 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3487 % GetVirtualPixels() returns an immutable pixel region. If the
3488 % region is successfully accessed, a pointer to it is returned, otherwise
3489 % NULL is returned. The returned pointer may point to a temporary working
3490 % copy of the pixels or it may point to the original pixels in memory.
3491 % Performance is maximized if the selected region is part of one row, or one
3492 % or more full rows, since there is opportunity to access the pixels in-place
3493 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3494 % returned pointer must *never* be deallocated by the user.
3496 % Pixels accessed via the returned pointer represent a simple array of type
3497 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3498 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3499 % access the meta-content (of type void) corresponding to the the
3502 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3504 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3505 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3506 % GetCacheViewAuthenticPixels() instead.
3508 % The format of the GetVirtualPixels() method is:
3510 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3511 % const ssize_t y,const size_t columns,const size_t rows,
3512 % ExceptionInfo *exception)
3514 % A description of each parameter follows:
3516 % o image: the image.
3518 % o x,y,columns,rows: These values define the perimeter of a region of
3521 % o exception: return any errors or warnings in this structure.
3524 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3525 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3526 ExceptionInfo *exception)
3532 id = GetOpenMPThreadId();
3537 assert(image != (const Image *) NULL);
3538 assert(image->signature == MagickSignature);
3539 assert(image->cache != (Cache) NULL);
3540 cache_info=(CacheInfo *) image->cache;
3541 assert(cache_info->signature == MagickSignature);
3542 if (cache_info->methods.get_virtual_pixel_handler !=
3543 (GetVirtualPixelHandler) NULL)
3544 return(cache_info->methods.get_virtual_pixel_handler(image,
3545 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3546 assert(id < (int) cache_info->number_threads);
3547 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3548 columns,rows,cache_info->nexus_info[id],exception);
3553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3557 + 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 %
3561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3563 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3564 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3566 % The format of the GetVirtualPixelsCache() method is:
3568 % Quantum *GetVirtualPixelsCache(const Image *image)
3570 % A description of each parameter follows:
3572 % o image: the image.
3575 static const Quantum *GetVirtualPixelsCache(const Image *image)
3581 id = GetOpenMPThreadId();
3583 assert(image != (const Image *) NULL);
3584 assert(image->signature == MagickSignature);
3585 assert(image->cache != (Cache) NULL);
3586 cache_info=(CacheInfo *) image->cache;
3587 assert(cache_info->signature == MagickSignature);
3588 assert(id < (int) cache_info->number_threads);
3589 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3597 + G e t V i r t u a l P i x e l s N e x u s %
3601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3603 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3606 % The format of the GetVirtualPixelsNexus() method is:
3608 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3609 % NexusInfo *nexus_info)
3611 % A description of each parameter follows:
3613 % o cache: the pixel cache.
3615 % o nexus_info: the cache nexus to return the colormap pixels.
3618 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3619 NexusInfo *nexus_info)
3624 assert(cache != (Cache) NULL);
3625 cache_info=(CacheInfo *) cache;
3626 assert(cache_info->signature == MagickSignature);
3627 if (cache_info->storage_class == UndefinedClass)
3628 return((Quantum *) NULL);
3629 return((const Quantum *) nexus_info->pixels);
3633 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3637 + O p e n P i x e l C a c h e %
3641 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3643 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3644 % dimensions, allocating space for the image pixels and optionally the
3645 % metacontent, and memory mapping the cache if it is disk based. The cache
3646 % nexus array is initialized as well.
3648 % The format of the OpenPixelCache() method is:
3650 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3651 % ExceptionInfo *exception)
3653 % A description of each parameter follows:
3655 % o image: the image.
3657 % o mode: ReadMode, WriteMode, or IOMode.
3659 % o exception: return any errors or warnings in this structure.
3663 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3665 cache_info->mapped=MagickFalse;
3666 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3667 cache_info->length);
3668 if (cache_info->pixels == (Quantum *) NULL)
3670 cache_info->mapped=MagickTrue;
3671 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3672 cache_info->length);
3676 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3686 cache_info=(CacheInfo *) image->cache;
3687 if (image->debug != MagickFalse)
3690 format[MaxTextExtent],
3691 message[MaxTextExtent];
3693 (void) FormatMagickSize(length,MagickFalse,format);
3694 (void) FormatLocaleString(message,MaxTextExtent,
3695 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3696 cache_info->cache_filename,cache_info->file,format);
3697 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3699 if (length != (MagickSizeType) ((MagickOffsetType) length))
3700 return(MagickFalse);
3701 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3703 return(MagickFalse);
3704 if ((MagickSizeType) extent >= length)
3706 offset=(MagickOffsetType) length-1;
3707 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3708 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3711 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3712 ExceptionInfo *exception)
3719 format[MaxTextExtent],
3720 message[MaxTextExtent];
3737 assert(image != (const Image *) NULL);
3738 assert(image->signature == MagickSignature);
3739 assert(image->cache != (Cache) NULL);
3740 if (image->debug != MagickFalse)
3741 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3742 if ((image->columns == 0) || (image->rows == 0))
3743 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3744 cache_info=(CacheInfo *) image->cache;
3745 assert(cache_info->signature == MagickSignature);
3746 source_info=(*cache_info);
3747 source_info.file=(-1);
3748 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3749 image->filename,(double) GetImageIndexInList(image));
3750 cache_info->storage_class=image->storage_class;
3751 cache_info->colorspace=image->colorspace;
3752 cache_info->matte=image->matte;
3753 cache_info->mask=image->mask;
3754 cache_info->rows=image->rows;
3755 cache_info->columns=image->columns;
3756 InitializePixelChannelMap(image);
3757 cache_info->number_channels=GetPixelChannels(image);
3758 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3759 sizeof(*image->channel_map));
3760 cache_info->metacontent_extent=image->metacontent_extent;
3761 cache_info->mode=mode;
3762 if (image->ping != MagickFalse)
3764 cache_info->type=PingCache;
3765 cache_info->pixels=(Quantum *) NULL;
3766 cache_info->metacontent=(void *) NULL;
3767 cache_info->length=0;
3770 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3771 packet_size=cache_info->number_channels*sizeof(Quantum);
3772 if (image->metacontent_extent != 0)
3773 packet_size+=cache_info->metacontent_extent;
3774 length=number_pixels*packet_size;
3775 columns=(size_t) (length/cache_info->rows/packet_size);
3776 if (cache_info->columns != columns)
3777 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3779 cache_info->length=length;
3780 p=cache_info->channel_map;
3781 q=source_info.channel_map;
3782 if ((cache_info->type != UndefinedCache) &&
3783 (cache_info->columns <= source_info.columns) &&
3784 (cache_info->rows <= source_info.rows) &&
3785 (cache_info->number_channels <= source_info.number_channels) &&
3786 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
3787 (cache_info->metacontent_extent <= source_info.metacontent_extent))
3790 Inline pixel cache clone optimization.
3792 if ((cache_info->columns == source_info.columns) &&
3793 (cache_info->rows == source_info.rows) &&
3794 (cache_info->number_channels == source_info.number_channels) &&
3795 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
3796 (cache_info->metacontent_extent == source_info.metacontent_extent))
3798 return(ClonePixelCachePixels(cache_info,&source_info,exception));
3800 status=AcquireMagickResource(AreaResource,cache_info->length);
3801 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3802 cache_info->metacontent_extent);
3803 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3805 status=AcquireMagickResource(MemoryResource,cache_info->length);
3806 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3807 (cache_info->type == MemoryCache))
3809 AllocatePixelCachePixels(cache_info);
3810 if (cache_info->pixels == (Quantum *) NULL)
3811 cache_info->pixels=source_info.pixels;
3815 Create memory pixel cache.
3818 if (image->debug != MagickFalse)
3820 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3821 (void) FormatLocaleString(message,MaxTextExtent,
3822 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3823 cache_info->filename,cache_info->mapped != MagickFalse ?
3824 "anonymous" : "heap",(double) cache_info->columns,(double)
3825 cache_info->rows,(double) cache_info->number_channels,
3827 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3830 cache_info->type=MemoryCache;
3831 cache_info->metacontent=(void *) NULL;
3832 if (cache_info->metacontent_extent != 0)
3833 cache_info->metacontent=(void *) (cache_info->pixels+
3834 number_pixels*cache_info->number_channels);
3835 if ((source_info.storage_class != UndefinedClass) &&
3838 status=ClonePixelCachePixels(cache_info,&source_info,
3840 RelinquishPixelCachePixels(&source_info);
3845 RelinquishMagickResource(MemoryResource,cache_info->length);
3848 Create pixel cache on disk.
3850 status=AcquireMagickResource(DiskResource,cache_info->length);
3851 if (status == MagickFalse)
3853 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3854 "CacheResourcesExhausted","`%s'",image->filename);
3855 return(MagickFalse);
3857 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3859 (void) ClosePixelCacheOnDisk(cache_info);
3860 *cache_info->cache_filename='\0';
3862 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3864 RelinquishMagickResource(DiskResource,cache_info->length);
3865 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3867 return(MagickFalse);
3869 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3870 cache_info->length);
3871 if (status == MagickFalse)
3873 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3875 return(MagickFalse);
3877 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3878 cache_info->metacontent_extent);
3879 if (length != (MagickSizeType) ((size_t) length))
3880 cache_info->type=DiskCache;
3883 status=AcquireMagickResource(MapResource,cache_info->length);
3884 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3885 (cache_info->type != MemoryCache))
3886 cache_info->type=DiskCache;
3889 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3890 cache_info->offset,(size_t) cache_info->length);
3891 if (cache_info->pixels == (Quantum *) NULL)
3893 cache_info->type=DiskCache;
3894 cache_info->pixels=source_info.pixels;
3899 Create file-backed memory-mapped pixel cache.
3902 (void) ClosePixelCacheOnDisk(cache_info);
3903 cache_info->type=MapCache;
3904 cache_info->mapped=MagickTrue;
3905 cache_info->metacontent=(void *) NULL;
3906 if (cache_info->metacontent_extent != 0)
3907 cache_info->metacontent=(void *) (cache_info->pixels+
3908 number_pixels*cache_info->number_channels);
3909 if ((source_info.storage_class != UndefinedClass) &&
3912 status=ClonePixelCachePixels(cache_info,&source_info,
3914 RelinquishPixelCachePixels(&source_info);
3916 if (image->debug != MagickFalse)
3918 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3919 (void) FormatLocaleString(message,MaxTextExtent,
3920 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
3921 cache_info->filename,cache_info->cache_filename,
3922 cache_info->file,(double) cache_info->columns,(double)
3923 cache_info->rows,(double) cache_info->number_channels,
3925 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3931 RelinquishMagickResource(MapResource,cache_info->length);
3934 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3936 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3937 RelinquishPixelCachePixels(&source_info);
3939 if (image->debug != MagickFalse)
3941 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3942 (void) FormatLocaleString(message,MaxTextExtent,
3943 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
3944 cache_info->cache_filename,cache_info->file,(double)
3945 cache_info->columns,(double) cache_info->rows,(double)
3946 cache_info->number_channels,format);
3947 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3957 + P e r s i s t P i x e l C a c h e %
3961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3963 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3964 % persistent pixel cache is one that resides on disk and is not destroyed
3965 % when the program exits.
3967 % The format of the PersistPixelCache() method is:
3969 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3970 % const MagickBooleanType attach,MagickOffsetType *offset,
3971 % ExceptionInfo *exception)
3973 % A description of each parameter follows:
3975 % o image: the image.
3977 % o filename: the persistent pixel cache filename.
3979 % o attach: A value other than zero initializes the persistent pixel cache.
3981 % o initialize: A value other than zero initializes the persistent pixel
3984 % o offset: the offset in the persistent cache to store pixels.
3986 % o exception: return any errors or warnings in this structure.
3989 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3990 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3991 ExceptionInfo *exception)
4006 assert(image != (Image *) NULL);
4007 assert(image->signature == MagickSignature);
4008 if (image->debug != MagickFalse)
4009 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4010 assert(image->cache != (void *) NULL);
4011 assert(filename != (const char *) NULL);
4012 assert(offset != (MagickOffsetType *) NULL);
4013 page_size=GetMagickPageSize();
4014 cache_info=(CacheInfo *) image->cache;
4015 assert(cache_info->signature == MagickSignature);
4016 if (attach != MagickFalse)
4019 Attach existing persistent pixel cache.
4021 if (image->debug != MagickFalse)
4022 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4023 "attach persistent cache");
4024 (void) CopyMagickString(cache_info->cache_filename,filename,
4026 cache_info->type=DiskCache;
4027 cache_info->offset=(*offset);
4028 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4029 return(MagickFalse);
4030 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4033 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4034 (cache_info->reference_count == 1))
4036 LockSemaphoreInfo(cache_info->semaphore);
4037 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4038 (cache_info->reference_count == 1))
4044 Usurp existing persistent pixel cache.
4046 status=rename_utf8(cache_info->cache_filename,filename);
4049 (void) CopyMagickString(cache_info->cache_filename,filename,
4051 *offset+=cache_info->length+page_size-(cache_info->length %
4053 UnlockSemaphoreInfo(cache_info->semaphore);
4054 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4055 if (image->debug != MagickFalse)
4056 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4057 "Usurp resident persistent cache");
4061 UnlockSemaphoreInfo(cache_info->semaphore);
4064 Clone persistent pixel cache.
4066 clone_image=(*image);
4067 clone_info=(CacheInfo *) clone_image.cache;
4068 image->cache=ClonePixelCache(cache_info);
4069 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4070 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4071 cache_info->type=DiskCache;
4072 cache_info->offset=(*offset);
4073 cache_info=(CacheInfo *) image->cache;
4074 status=OpenPixelCache(image,IOMode,exception);
4075 if (status != MagickFalse)
4076 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4077 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4078 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4087 + 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 %
4091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4093 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4094 % defined by the region rectangle and returns a pointer to the region. This
4095 % region is subsequently transferred from the pixel cache with
4096 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4097 % pixels are transferred, otherwise a NULL is returned.
4099 % The format of the QueueAuthenticPixelCacheNexus() method is:
4101 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4102 % const ssize_t y,const size_t columns,const size_t rows,
4103 % const MagickBooleanType clone,NexusInfo *nexus_info,
4104 % ExceptionInfo *exception)
4106 % A description of each parameter follows:
4108 % o image: the image.
4110 % o x,y,columns,rows: These values define the perimeter of a region of
4113 % o nexus_info: the cache nexus to set.
4115 % o clone: clone the pixel cache.
4117 % o exception: return any errors or warnings in this structure.
4120 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4121 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4122 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4137 Validate pixel cache geometry.
4139 assert(image != (const Image *) NULL);
4140 assert(image->signature == MagickSignature);
4141 assert(image->cache != (Cache) NULL);
4142 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4143 if (cache_info == (Cache) NULL)
4144 return((Quantum *) NULL);
4145 assert(cache_info->signature == MagickSignature);
4146 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4148 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4149 "NoPixelsDefinedInCache","`%s'",image->filename);
4150 return((Quantum *) NULL);
4152 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4153 (y >= (ssize_t) cache_info->rows))
4155 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4156 "PixelsAreNotAuthentic","`%s'",image->filename);
4157 return((Quantum *) NULL);
4159 offset=(MagickOffsetType) y*cache_info->columns+x;
4161 return((Quantum *) NULL);
4162 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4163 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4164 if ((MagickSizeType) offset >= number_pixels)
4165 return((Quantum *) NULL);
4171 region.width=columns;
4173 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4181 + 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 %
4185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4187 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4188 % defined by the region rectangle and returns a pointer to the region. This
4189 % region is subsequently transferred from the pixel cache with
4190 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4191 % pixels are transferred, otherwise a NULL is returned.
4193 % The format of the QueueAuthenticPixelsCache() method is:
4195 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4196 % const ssize_t y,const size_t columns,const size_t rows,
4197 % ExceptionInfo *exception)
4199 % A description of each parameter follows:
4201 % o image: the image.
4203 % o x,y,columns,rows: These values define the perimeter of a region of
4206 % o exception: return any errors or warnings in this structure.
4209 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4210 const ssize_t y,const size_t columns,const size_t rows,
4211 ExceptionInfo *exception)
4217 id = GetOpenMPThreadId();
4222 assert(image != (const Image *) NULL);
4223 assert(image->signature == MagickSignature);
4224 assert(image->cache != (Cache) NULL);
4225 cache_info=(CacheInfo *) image->cache;
4226 assert(cache_info->signature == MagickSignature);
4227 assert(id < (int) cache_info->number_threads);
4228 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4229 cache_info->nexus_info[id],exception);
4234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4238 % Q u e u e A u t h e n t i c P i x e l s %
4242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4244 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4245 % successfully initialized a pointer to a Quantum array representing the
4246 % region is returned, otherwise NULL is returned. The returned pointer may
4247 % point to a temporary working buffer for the pixels or it may point to the
4248 % final location of the pixels in memory.
4250 % Write-only access means that any existing pixel values corresponding to
4251 % the region are ignored. This is useful if the initial image is being
4252 % created from scratch, or if the existing pixel values are to be
4253 % completely replaced without need to refer to their pre-existing values.
4254 % The application is free to read and write the pixel buffer returned by
4255 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4256 % initialize the pixel array values. Initializing pixel array values is the
4257 % application's responsibility.
4259 % Performance is maximized if the selected region is part of one row, or
4260 % one or more full rows, since then there is opportunity to access the
4261 % pixels in-place (without a copy) if the image is in memory, or in a
4262 % memory-mapped file. The returned pointer must *never* be deallocated
4265 % Pixels accessed via the returned pointer represent a simple array of type
4266 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4267 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4268 % obtain the meta-content (of type void) corresponding to the region.
4269 % Once the Quantum (and/or Quantum) array has been updated, the
4270 % changes must be saved back to the underlying image using
4271 % SyncAuthenticPixels() or they may be lost.
4273 % The format of the QueueAuthenticPixels() method is:
4275 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4276 % const ssize_t y,const size_t columns,const size_t rows,
4277 % ExceptionInfo *exception)
4279 % A description of each parameter follows:
4281 % o image: the image.
4283 % o x,y,columns,rows: These values define the perimeter of a region of
4286 % o exception: return any errors or warnings in this structure.
4289 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4290 const ssize_t y,const size_t columns,const size_t rows,
4291 ExceptionInfo *exception)
4297 id = GetOpenMPThreadId();
4302 assert(image != (Image *) NULL);
4303 assert(image->signature == MagickSignature);
4304 assert(image->cache != (Cache) NULL);
4305 cache_info=(CacheInfo *) image->cache;
4306 assert(cache_info->signature == MagickSignature);
4307 if (cache_info->methods.queue_authentic_pixels_handler !=
4308 (QueueAuthenticPixelsHandler) NULL)
4310 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4311 columns,rows,exception);
4314 assert(id < (int) cache_info->number_threads);
4315 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4316 cache_info->nexus_info[id],exception);
4321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4325 + 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 %
4329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4331 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4334 % The format of the ReadPixelCacheMetacontent() method is:
4336 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4337 % NexusInfo *nexus_info,ExceptionInfo *exception)
4339 % A description of each parameter follows:
4341 % o cache_info: the pixel cache.
4343 % o nexus_info: the cache nexus to read the metacontent.
4345 % o exception: return any errors or warnings in this structure.
4348 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4349 NexusInfo *nexus_info,ExceptionInfo *exception)
4362 register unsigned char
4368 if (cache_info->metacontent_extent == 0)
4369 return(MagickFalse);
4370 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4372 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4373 nexus_info->region.x;
4374 length=(MagickSizeType) nexus_info->region.width*
4375 cache_info->metacontent_extent;
4376 rows=nexus_info->region.height;
4378 q=(unsigned char *) nexus_info->metacontent;
4379 switch (cache_info->type)
4384 register unsigned char
4388 Read meta-content from memory.
4390 if ((cache_info->columns == nexus_info->region.width) &&
4391 (extent == (MagickSizeType) ((size_t) extent)))
4396 p=(unsigned char *) cache_info->metacontent+offset*
4397 cache_info->metacontent_extent;
4398 for (y=0; y < (ssize_t) rows; y++)
4400 (void) memcpy(q,p,(size_t) length);
4401 p+=cache_info->metacontent_extent*cache_info->columns;
4402 q+=cache_info->metacontent_extent*nexus_info->region.width;
4409 Read meta content from disk.
4411 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4413 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4414 cache_info->cache_filename);
4415 return(MagickFalse);
4417 if ((cache_info->columns == nexus_info->region.width) &&
4418 (extent <= MagickMaxBufferExtent))
4423 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4424 for (y=0; y < (ssize_t) rows; y++)
4426 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4427 cache_info->number_channels*sizeof(Quantum)+offset*
4428 cache_info->metacontent_extent,length,(unsigned char *) q);
4429 if ((MagickSizeType) count != length)
4431 offset+=cache_info->columns;
4432 q+=cache_info->metacontent_extent*nexus_info->region.width;
4434 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4435 (void) ClosePixelCacheOnDisk(cache_info);
4436 if (y < (ssize_t) rows)
4438 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4439 cache_info->cache_filename);
4440 return(MagickFalse);
4447 if ((cache_info->debug != MagickFalse) &&
4448 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4449 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4450 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4451 nexus_info->region.width,(double) nexus_info->region.height,(double)
4452 nexus_info->region.x,(double) nexus_info->region.y);
4457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4461 + R e a d P i x e l C a c h e P i x e l s %
4465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4467 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4470 % The format of the ReadPixelCachePixels() method is:
4472 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4473 % NexusInfo *nexus_info,ExceptionInfo *exception)
4475 % A description of each parameter follows:
4477 % o cache_info: the pixel cache.
4479 % o nexus_info: the cache nexus to read the pixels.
4481 % o exception: return any errors or warnings in this structure.
4484 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4485 NexusInfo *nexus_info,ExceptionInfo *exception)
4504 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4506 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4507 nexus_info->region.x;
4508 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4510 rows=nexus_info->region.height;
4512 q=nexus_info->pixels;
4513 switch (cache_info->type)
4522 Read pixels from memory.
4524 if ((cache_info->columns == nexus_info->region.width) &&
4525 (extent == (MagickSizeType) ((size_t) extent)))
4530 p=cache_info->pixels+offset*cache_info->number_channels;
4531 for (y=0; y < (ssize_t) rows; y++)
4533 (void) memcpy(q,p,(size_t) length);
4534 p+=cache_info->number_channels*cache_info->columns;
4535 q+=cache_info->number_channels*nexus_info->region.width;
4542 Read pixels from disk.
4544 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4546 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4547 cache_info->cache_filename);
4548 return(MagickFalse);
4550 if ((cache_info->columns == nexus_info->region.width) &&
4551 (extent <= MagickMaxBufferExtent))
4556 for (y=0; y < (ssize_t) rows; y++)
4558 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4559 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4560 if ((MagickSizeType) count != length)
4562 offset+=cache_info->columns;
4563 q+=cache_info->number_channels*nexus_info->region.width;
4565 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4566 (void) ClosePixelCacheOnDisk(cache_info);
4567 if (y < (ssize_t) rows)
4569 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4570 cache_info->cache_filename);
4571 return(MagickFalse);
4578 if ((cache_info->debug != MagickFalse) &&
4579 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4580 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4581 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4582 nexus_info->region.width,(double) nexus_info->region.height,(double)
4583 nexus_info->region.x,(double) nexus_info->region.y);
4588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4592 + R e f e r e n c e P i x e l C a c h e %
4596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4598 % ReferencePixelCache() increments the reference count associated with the
4599 % pixel cache returning a pointer to the cache.
4601 % The format of the ReferencePixelCache method is:
4603 % Cache ReferencePixelCache(Cache cache_info)
4605 % A description of each parameter follows:
4607 % o cache_info: the pixel cache.
4610 MagickPrivate Cache ReferencePixelCache(Cache cache)
4615 assert(cache != (Cache *) NULL);
4616 cache_info=(CacheInfo *) cache;
4617 assert(cache_info->signature == MagickSignature);
4618 LockSemaphoreInfo(cache_info->semaphore);
4619 cache_info->reference_count++;
4620 UnlockSemaphoreInfo(cache_info->semaphore);
4625 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4629 + S e t P i x e l C a c h e M e t h o d s %
4633 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4635 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4637 % The format of the SetPixelCacheMethods() method is:
4639 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4641 % A description of each parameter follows:
4643 % o cache: the pixel cache.
4645 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4648 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4653 GetOneAuthenticPixelFromHandler
4654 get_one_authentic_pixel_from_handler;
4656 GetOneVirtualPixelFromHandler
4657 get_one_virtual_pixel_from_handler;
4660 Set cache pixel methods.
4662 assert(cache != (Cache) NULL);
4663 assert(cache_methods != (CacheMethods *) NULL);
4664 cache_info=(CacheInfo *) cache;
4665 assert(cache_info->signature == MagickSignature);
4666 if (cache_info->debug != MagickFalse)
4667 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4668 cache_info->filename);
4669 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4670 cache_info->methods.get_virtual_pixel_handler=
4671 cache_methods->get_virtual_pixel_handler;
4672 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4673 cache_info->methods.destroy_pixel_handler=
4674 cache_methods->destroy_pixel_handler;
4675 if (cache_methods->get_virtual_metacontent_from_handler !=
4676 (GetVirtualMetacontentFromHandler) NULL)
4677 cache_info->methods.get_virtual_metacontent_from_handler=
4678 cache_methods->get_virtual_metacontent_from_handler;
4679 if (cache_methods->get_authentic_pixels_handler !=
4680 (GetAuthenticPixelsHandler) NULL)
4681 cache_info->methods.get_authentic_pixels_handler=
4682 cache_methods->get_authentic_pixels_handler;
4683 if (cache_methods->queue_authentic_pixels_handler !=
4684 (QueueAuthenticPixelsHandler) NULL)
4685 cache_info->methods.queue_authentic_pixels_handler=
4686 cache_methods->queue_authentic_pixels_handler;
4687 if (cache_methods->sync_authentic_pixels_handler !=
4688 (SyncAuthenticPixelsHandler) NULL)
4689 cache_info->methods.sync_authentic_pixels_handler=
4690 cache_methods->sync_authentic_pixels_handler;
4691 if (cache_methods->get_authentic_pixels_from_handler !=
4692 (GetAuthenticPixelsFromHandler) NULL)
4693 cache_info->methods.get_authentic_pixels_from_handler=
4694 cache_methods->get_authentic_pixels_from_handler;
4695 if (cache_methods->get_authentic_metacontent_from_handler !=
4696 (GetAuthenticMetacontentFromHandler) NULL)
4697 cache_info->methods.get_authentic_metacontent_from_handler=
4698 cache_methods->get_authentic_metacontent_from_handler;
4699 get_one_virtual_pixel_from_handler=
4700 cache_info->methods.get_one_virtual_pixel_from_handler;
4701 if (get_one_virtual_pixel_from_handler !=
4702 (GetOneVirtualPixelFromHandler) NULL)
4703 cache_info->methods.get_one_virtual_pixel_from_handler=
4704 cache_methods->get_one_virtual_pixel_from_handler;
4705 get_one_authentic_pixel_from_handler=
4706 cache_methods->get_one_authentic_pixel_from_handler;
4707 if (get_one_authentic_pixel_from_handler !=
4708 (GetOneAuthenticPixelFromHandler) NULL)
4709 cache_info->methods.get_one_authentic_pixel_from_handler=
4710 cache_methods->get_one_authentic_pixel_from_handler;
4714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4718 + S e t P i x e l C a c h e N e x u s P i x e l s %
4722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4724 % SetPixelCacheNexusPixels() defines the region of the cache for the
4725 % specified cache nexus.
4727 % The format of the SetPixelCacheNexusPixels() method is:
4729 % Quantum SetPixelCacheNexusPixels(const Image *image,
4730 % const RectangleInfo *region,NexusInfo *nexus_info,
4731 % ExceptionInfo *exception)
4733 % A description of each parameter follows:
4735 % o image: the image.
4737 % o region: A pointer to the RectangleInfo structure that defines the
4738 % region of this particular cache nexus.
4740 % o nexus_info: the cache nexus to set.
4742 % o exception: return any errors or warnings in this structure.
4746 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4747 NexusInfo *nexus_info,ExceptionInfo *exception)
4749 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4750 return(MagickFalse);
4751 nexus_info->mapped=MagickFalse;
4752 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
4753 nexus_info->length);
4754 if (nexus_info->cache == (Quantum *) NULL)
4756 nexus_info->mapped=MagickTrue;
4757 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4758 nexus_info->length);
4760 if (nexus_info->cache == (Quantum *) NULL)
4762 (void) ThrowMagickException(exception,GetMagickModule(),
4763 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4764 cache_info->filename);
4765 return(MagickFalse);
4770 static Quantum *SetPixelCacheNexusPixels(const Image *image,
4771 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4783 cache_info=(CacheInfo *) image->cache;
4784 assert(cache_info->signature == MagickSignature);
4785 if (cache_info->type == UndefinedCache)
4786 return((Quantum *) NULL);
4787 nexus_info->region=(*region);
4788 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
4794 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4795 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4796 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4797 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4798 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4799 ((nexus_info->region.width == cache_info->columns) ||
4800 ((nexus_info->region.width % cache_info->columns) == 0)))))
4806 Pixels are accessed directly from memory.
4808 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4809 nexus_info->region.x;
4810 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4812 nexus_info->metacontent=(void *) NULL;
4813 if (cache_info->metacontent_extent != 0)
4814 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4815 offset*cache_info->metacontent_extent;
4816 return(nexus_info->pixels);
4820 Pixels are stored in a cache region until they are synced to the cache.
4822 number_pixels=(MagickSizeType) nexus_info->region.width*
4823 nexus_info->region.height;
4824 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4825 if (cache_info->metacontent_extent != 0)
4826 length+=number_pixels*cache_info->metacontent_extent;
4827 if (nexus_info->cache == (Quantum *) NULL)
4829 nexus_info->length=length;
4830 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4831 if (status == MagickFalse)
4833 nexus_info->length=0;
4834 return((Quantum *) NULL);
4838 if (nexus_info->length != length)
4840 RelinquishCacheNexusPixels(nexus_info);
4841 nexus_info->length=length;
4842 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4843 if (status == MagickFalse)
4845 nexus_info->length=0;
4846 return((Quantum *) NULL);
4849 nexus_info->pixels=nexus_info->cache;
4850 nexus_info->metacontent=(void *) NULL;
4851 if (cache_info->metacontent_extent != 0)
4852 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4853 cache_info->number_channels);
4854 return(nexus_info->pixels);
4858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4862 % 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 %
4866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4868 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4869 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4870 % access that is outside the boundaries of the image cache.
4872 % The format of the SetPixelCacheVirtualMethod() method is:
4874 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4875 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4877 % A description of each parameter follows:
4879 % o image: the image.
4881 % o virtual_pixel_method: choose the type of virtual pixel.
4883 % o exception: return any errors or warnings in this structure.
4887 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4888 ExceptionInfo *exception)
4899 assert(image != (Image *) NULL);
4900 assert(image->signature == MagickSignature);
4901 if (image->debug != MagickFalse)
4902 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4903 assert(image->cache != (Cache) NULL);
4904 cache_info=(CacheInfo *) image->cache;
4905 assert(cache_info->signature == MagickSignature);
4906 image->matte=MagickTrue;
4908 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4909 #pragma omp parallel for schedule(static,4) shared(status)
4911 for (y=0; y < (ssize_t) image->rows; y++)
4914 id = GetOpenMPThreadId();
4922 if (status == MagickFalse)
4924 q=GetAuthenticPixelCacheNexus(image,0,y,image->columns,1,
4925 cache_info->nexus_info[id],exception);
4926 if (q == (Quantum *) NULL)
4931 for (x=0; x < (ssize_t) image->columns; x++)
4933 SetPixelAlpha(image,alpha,q);
4934 q+=GetPixelChannels(image);
4936 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4942 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4943 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4951 assert(image != (Image *) NULL);
4952 assert(image->signature == MagickSignature);
4953 if (image->debug != MagickFalse)
4954 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4955 assert(image->cache != (Cache) NULL);
4956 cache_info=(CacheInfo *) image->cache;
4957 assert(cache_info->signature == MagickSignature);
4958 method=cache_info->virtual_pixel_method;
4959 cache_info->virtual_pixel_method=virtual_pixel_method;
4960 switch (virtual_pixel_method)
4962 case BackgroundVirtualPixelMethod:
4964 if ((image->background_color.matte != MagickFalse) &&
4965 (image->matte == MagickFalse))
4966 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4969 case TransparentVirtualPixelMethod:
4971 if (image->matte == MagickFalse)
4972 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4986 + 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 %
4990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4992 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4993 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4994 % is synced, otherwise MagickFalse.
4996 % The format of the SyncAuthenticPixelCacheNexus() method is:
4998 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
4999 % NexusInfo *nexus_info,ExceptionInfo *exception)
5001 % A description of each parameter follows:
5003 % o image: the image.
5005 % o nexus_info: the cache nexus to sync.
5007 % o exception: return any errors or warnings in this structure.
5010 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5011 NexusInfo *nexus_info,ExceptionInfo *exception)
5020 Transfer pixels to the cache.
5022 assert(image != (Image *) NULL);
5023 assert(image->signature == MagickSignature);
5024 if (image->cache == (Cache) NULL)
5025 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5026 cache_info=(CacheInfo *) image->cache;
5027 assert(cache_info->signature == MagickSignature);
5028 if (cache_info->type == UndefinedCache)
5029 return(MagickFalse);
5030 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5032 assert(cache_info->signature == MagickSignature);
5033 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5034 if ((cache_info->metacontent_extent != 0) &&
5035 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5036 return(MagickFalse);
5041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5045 + S y n c A u t h e n t i c P i x e l C a c h e %
5049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5051 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5052 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5053 % otherwise MagickFalse.
5055 % The format of the SyncAuthenticPixelsCache() method is:
5057 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5058 % ExceptionInfo *exception)
5060 % A description of each parameter follows:
5062 % o image: the image.
5064 % o exception: return any errors or warnings in this structure.
5067 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5068 ExceptionInfo *exception)
5074 id = GetOpenMPThreadId();
5079 assert(image != (Image *) NULL);
5080 assert(image->signature == MagickSignature);
5081 assert(image->cache != (Cache) NULL);
5082 cache_info=(CacheInfo *) image->cache;
5083 assert(cache_info->signature == MagickSignature);
5084 assert(id < (int) cache_info->number_threads);
5085 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5095 % S y n c A u t h e n t i c P i x e l s %
5099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5101 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5102 % The method returns MagickTrue if the pixel region is flushed, otherwise
5105 % The format of the SyncAuthenticPixels() method is:
5107 % MagickBooleanType SyncAuthenticPixels(Image *image,
5108 % ExceptionInfo *exception)
5110 % A description of each parameter follows:
5112 % o image: the image.
5114 % o exception: return any errors or warnings in this structure.
5117 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5118 ExceptionInfo *exception)
5124 id = GetOpenMPThreadId();
5129 assert(image != (Image *) NULL);
5130 assert(image->signature == MagickSignature);
5131 assert(image->cache != (Cache) NULL);
5132 cache_info=(CacheInfo *) image->cache;
5133 assert(cache_info->signature == MagickSignature);
5134 if (cache_info->methods.sync_authentic_pixels_handler !=
5135 (SyncAuthenticPixelsHandler) NULL)
5137 status=cache_info->methods.sync_authentic_pixels_handler(image,
5141 assert(id < (int) cache_info->number_threads);
5142 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5152 + S y n c I m a g e P i x e l C a c h e %
5156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5158 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5159 % The method returns MagickTrue if the pixel region is flushed, otherwise
5162 % The format of the SyncImagePixelCache() method is:
5164 % MagickBooleanType SyncImagePixelCache(Image *image,
5165 % ExceptionInfo *exception)
5167 % A description of each parameter follows:
5169 % o image: the image.
5171 % o exception: return any errors or warnings in this structure.
5174 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5175 ExceptionInfo *exception)
5180 assert(image != (Image *) NULL);
5181 assert(exception != (ExceptionInfo *) NULL);
5182 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5183 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5191 + 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 %
5195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5197 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5198 % of the pixel cache.
5200 % The format of the WritePixelCacheMetacontent() method is:
5202 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5203 % NexusInfo *nexus_info,ExceptionInfo *exception)
5205 % A description of each parameter follows:
5207 % o cache_info: the pixel cache.
5209 % o nexus_info: the cache nexus to write the meta-content.
5211 % o exception: return any errors or warnings in this structure.
5214 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5215 NexusInfo *nexus_info,ExceptionInfo *exception)
5225 register const unsigned char
5234 if (cache_info->metacontent_extent == 0)
5235 return(MagickFalse);
5236 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5238 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5239 nexus_info->region.x;
5240 length=(MagickSizeType) nexus_info->region.width*
5241 cache_info->metacontent_extent;
5242 rows=nexus_info->region.height;
5243 extent=(MagickSizeType) length*rows;
5244 p=(unsigned char *) nexus_info->metacontent;
5245 switch (cache_info->type)
5250 register unsigned char
5254 Write associated pixels to memory.
5256 if ((cache_info->columns == nexus_info->region.width) &&
5257 (extent == (MagickSizeType) ((size_t) extent)))
5262 q=(unsigned char *) cache_info->metacontent+offset*
5263 cache_info->metacontent_extent;
5264 for (y=0; y < (ssize_t) rows; y++)
5266 (void) memcpy(q,p,(size_t) length);
5267 p+=nexus_info->region.width*cache_info->metacontent_extent;
5268 q+=cache_info->columns*cache_info->metacontent_extent;
5275 Write associated pixels to disk.
5277 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5279 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5280 cache_info->cache_filename);
5281 return(MagickFalse);
5283 if ((cache_info->columns == nexus_info->region.width) &&
5284 (extent <= MagickMaxBufferExtent))
5289 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5290 for (y=0; y < (ssize_t) rows; y++)
5292 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5293 cache_info->number_channels*sizeof(Quantum)+offset*
5294 cache_info->metacontent_extent,length,(const unsigned char *) p);
5295 if ((MagickSizeType) count != length)
5297 p+=nexus_info->region.width*cache_info->metacontent_extent;
5298 offset+=cache_info->columns;
5300 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5301 (void) ClosePixelCacheOnDisk(cache_info);
5302 if (y < (ssize_t) rows)
5304 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5305 cache_info->cache_filename);
5306 return(MagickFalse);
5313 if ((cache_info->debug != MagickFalse) &&
5314 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5315 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5316 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5317 nexus_info->region.width,(double) nexus_info->region.height,(double)
5318 nexus_info->region.x,(double) nexus_info->region.y);
5323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5327 + W r i t e C a c h e P i x e l s %
5331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5333 % WritePixelCachePixels() writes image pixels to the specified region of the
5336 % The format of the WritePixelCachePixels() method is:
5338 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5339 % NexusInfo *nexus_info,ExceptionInfo *exception)
5341 % A description of each parameter follows:
5343 % o cache_info: the pixel cache.
5345 % o nexus_info: the cache nexus to write the pixels.
5347 % o exception: return any errors or warnings in this structure.
5350 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5351 NexusInfo *nexus_info,ExceptionInfo *exception)
5361 register const Quantum
5370 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5372 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5373 nexus_info->region.x;
5374 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5376 rows=nexus_info->region.height;
5378 p=nexus_info->pixels;
5379 switch (cache_info->type)
5388 Write pixels to memory.
5390 if ((cache_info->columns == nexus_info->region.width) &&
5391 (extent == (MagickSizeType) ((size_t) extent)))
5396 q=cache_info->pixels+offset*cache_info->number_channels;
5397 for (y=0; y < (ssize_t) rows; y++)
5399 (void) memcpy(q,p,(size_t) length);
5400 p+=nexus_info->region.width*cache_info->number_channels;
5401 q+=cache_info->columns*cache_info->number_channels;
5408 Write pixels to disk.
5410 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5412 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5413 cache_info->cache_filename);
5414 return(MagickFalse);
5416 if ((cache_info->columns == nexus_info->region.width) &&
5417 (extent <= MagickMaxBufferExtent))
5422 for (y=0; y < (ssize_t) rows; y++)
5424 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5425 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5427 if ((MagickSizeType) count != length)
5429 p+=nexus_info->region.width*cache_info->number_channels;
5430 offset+=cache_info->columns;
5432 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5433 (void) ClosePixelCacheOnDisk(cache_info);
5434 if (y < (ssize_t) rows)
5436 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5437 cache_info->cache_filename);
5438 return(MagickFalse);
5445 if ((cache_info->debug != MagickFalse) &&
5446 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5447 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5448 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5449 nexus_info->region.width,(double) nexus_info->region.height,(double)
5450 nexus_info->region.x,(double) nexus_info->region.y);