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 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2863 (GetVirtualMetacontentFromHandler) NULL)
2865 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(
2867 return(metacontent);
2869 assert(id < (int) cache_info->number_threads);
2870 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2871 cache_info->nexus_info[id]);
2872 return(metacontent);
2876 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2880 + G e t V i r t u a l P i x e l s F r o m N e x u s %
2884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2886 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
2887 % pixel cache as defined by the geometry parameters. A pointer to the pixels
2888 % is returned if the pixels are transferred, otherwise a NULL is returned.
2890 % The format of the GetVirtualPixelsFromNexus() method is:
2892 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
2893 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2894 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
2895 % ExceptionInfo *exception)
2897 % A description of each parameter follows:
2899 % o image: the image.
2901 % o virtual_pixel_method: the virtual pixel method.
2903 % o x,y,columns,rows: These values define the perimeter of a region of
2906 % o nexus_info: the cache nexus to acquire.
2908 % o exception: return any errors or warnings in this structure.
2915 0, 48, 12, 60, 3, 51, 15, 63,
2916 32, 16, 44, 28, 35, 19, 47, 31,
2917 8, 56, 4, 52, 11, 59, 7, 55,
2918 40, 24, 36, 20, 43, 27, 39, 23,
2919 2, 50, 14, 62, 1, 49, 13, 61,
2920 34, 18, 46, 30, 33, 17, 45, 29,
2921 10, 58, 6, 54, 9, 57, 5, 53,
2922 42, 26, 38, 22, 41, 25, 37, 21
2925 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
2930 index=x+DitherMatrix[x & 0x07]-32L;
2933 if (index >= (ssize_t) columns)
2934 return((ssize_t) columns-1L);
2938 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
2943 index=y+DitherMatrix[y & 0x07]-32L;
2946 if (index >= (ssize_t) rows)
2947 return((ssize_t) rows-1L);
2951 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
2955 if (x >= (ssize_t) columns)
2956 return((ssize_t) (columns-1));
2960 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
2964 if (y >= (ssize_t) rows)
2965 return((ssize_t) (rows-1));
2969 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
2971 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2974 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
2976 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2979 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
2980 const size_t extent)
2986 Compute the remainder of dividing offset by extent. It returns not only
2987 the quotient (tile the offset falls in) but also the positive remainer
2988 within that tile such that 0 <= remainder < extent. This method is
2989 essentially a ldiv() using a floored modulo division rather than the
2990 normal default truncated modulo division.
2992 modulo.quotient=offset/(ssize_t) extent;
2995 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
2999 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3000 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3001 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3002 ExceptionInfo *exception)
3019 virtual_pixel[CompositePixelChannel];
3024 register const Quantum
3037 register unsigned char
3044 *virtual_metacontent;
3049 assert(image != (const Image *) NULL);
3050 assert(image->signature == MagickSignature);
3051 assert(image->cache != (Cache) NULL);
3052 cache_info=(CacheInfo *) image->cache;
3053 assert(cache_info->signature == MagickSignature);
3054 if (cache_info->type == UndefinedCache)
3055 return((const Quantum *) NULL);
3058 region.width=columns;
3060 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3061 if (pixels == (Quantum *) NULL)
3062 return((const Quantum *) NULL);
3064 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3065 nexus_info->region.x;
3066 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3067 nexus_info->region.width-1L;
3068 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3069 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3070 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3071 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3077 Pixel request is inside cache extents.
3079 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3081 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3082 if (status == MagickFalse)
3083 return((const Quantum *) NULL);
3084 if (cache_info->metacontent_extent != 0)
3086 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3087 if (status == MagickFalse)
3088 return((const Quantum *) NULL);
3093 Pixel request is outside cache extents.
3095 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3096 virtual_nexus=AcquirePixelCacheNexus(1);
3097 if (virtual_nexus == (NexusInfo **) NULL)
3099 if (virtual_nexus != (NexusInfo **) NULL)
3100 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3101 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3102 "UnableToGetCacheNexus","`%s'",image->filename);
3103 return((const Quantum *) NULL);
3105 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3106 sizeof(*virtual_pixel));
3107 virtual_metacontent=(void *) NULL;
3108 switch (virtual_pixel_method)
3110 case BackgroundVirtualPixelMethod:
3111 case BlackVirtualPixelMethod:
3112 case GrayVirtualPixelMethod:
3113 case TransparentVirtualPixelMethod:
3114 case MaskVirtualPixelMethod:
3115 case WhiteVirtualPixelMethod:
3116 case EdgeVirtualPixelMethod:
3117 case CheckerTileVirtualPixelMethod:
3118 case HorizontalTileVirtualPixelMethod:
3119 case VerticalTileVirtualPixelMethod:
3121 if (cache_info->metacontent_extent != 0)
3124 Acquire a metacontent buffer.
3126 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3127 cache_info->metacontent_extent);
3128 if (virtual_metacontent == (void *) NULL)
3130 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3131 (void) ThrowMagickException(exception,GetMagickModule(),
3132 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3133 return((const Quantum *) NULL);
3135 (void) ResetMagickMemory(virtual_metacontent,0,
3136 cache_info->metacontent_extent);
3138 switch (virtual_pixel_method)
3140 case BlackVirtualPixelMethod:
3142 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3143 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3144 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3147 case GrayVirtualPixelMethod:
3149 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3150 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3152 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3155 case TransparentVirtualPixelMethod:
3157 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3158 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3159 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3162 case MaskVirtualPixelMethod:
3163 case WhiteVirtualPixelMethod:
3165 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3166 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3167 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3172 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3174 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3176 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3178 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3180 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3190 for (v=0; v < (ssize_t) rows; v++)
3192 for (u=0; u < (ssize_t) columns; u+=length)
3194 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3195 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3196 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3204 Transfer a single pixel.
3206 length=(MagickSizeType) 1;
3207 switch (virtual_pixel_method)
3211 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3212 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3213 1UL,1UL,*virtual_nexus,exception);
3214 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3217 case RandomVirtualPixelMethod:
3219 if (cache_info->random_info == (RandomInfo *) NULL)
3220 cache_info->random_info=AcquireRandomInfo();
3221 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3222 RandomX(cache_info->random_info,cache_info->columns),
3223 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3224 *virtual_nexus,exception);
3225 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3228 case DitherVirtualPixelMethod:
3230 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3231 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3232 1UL,1UL,*virtual_nexus,exception);
3233 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3236 case TileVirtualPixelMethod:
3238 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3239 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3240 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3241 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3243 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3246 case MirrorVirtualPixelMethod:
3248 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3249 if ((x_modulo.quotient & 0x01) == 1L)
3250 x_modulo.remainder=(ssize_t) cache_info->columns-
3251 x_modulo.remainder-1L;
3252 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3253 if ((y_modulo.quotient & 0x01) == 1L)
3254 y_modulo.remainder=(ssize_t) cache_info->rows-
3255 y_modulo.remainder-1L;
3256 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3257 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3259 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3262 case HorizontalTileEdgeVirtualPixelMethod:
3264 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3265 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3266 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3267 *virtual_nexus,exception);
3268 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3271 case VerticalTileEdgeVirtualPixelMethod:
3273 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3274 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3275 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3276 *virtual_nexus,exception);
3277 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3280 case BackgroundVirtualPixelMethod:
3281 case BlackVirtualPixelMethod:
3282 case GrayVirtualPixelMethod:
3283 case TransparentVirtualPixelMethod:
3284 case MaskVirtualPixelMethod:
3285 case WhiteVirtualPixelMethod:
3288 r=virtual_metacontent;
3291 case EdgeVirtualPixelMethod:
3292 case CheckerTileVirtualPixelMethod:
3294 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3295 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3296 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3299 r=virtual_metacontent;
3302 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3303 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3305 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3308 case HorizontalTileVirtualPixelMethod:
3310 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3313 r=virtual_metacontent;
3316 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3317 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3318 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3319 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3321 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3324 case VerticalTileVirtualPixelMethod:
3326 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3329 r=virtual_metacontent;
3332 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3333 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3334 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3335 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3337 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3341 if (p == (const Quantum *) NULL)
3343 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3345 q+=cache_info->number_channels;
3346 if ((s != (void *) NULL) && (r != (const void *) NULL))
3348 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3349 s+=cache_info->metacontent_extent;
3354 Transfer a run of pixels.
3356 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3357 length,1UL,*virtual_nexus,exception);
3358 if (p == (const Quantum *) NULL)
3360 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3361 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3362 q+=length*cache_info->number_channels;
3363 if ((r != (void *) NULL) && (s != (const void *) NULL))
3365 (void) memcpy(s,r,(size_t) length);
3366 s+=length*cache_info->metacontent_extent;
3373 if (virtual_metacontent != (void *) NULL)
3374 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3375 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3384 + G e t V i r t u a l P i x e l C a c h e %
3388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3390 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3391 % cache as defined by the geometry parameters. A pointer to the pixels
3392 % is returned if the pixels are transferred, otherwise a NULL is returned.
3394 % The format of the GetVirtualPixelCache() method is:
3396 % const Quantum *GetVirtualPixelCache(const Image *image,
3397 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3398 % const ssize_t y,const size_t columns,const size_t rows,
3399 % ExceptionInfo *exception)
3401 % A description of each parameter follows:
3403 % o image: the image.
3405 % o virtual_pixel_method: the virtual pixel method.
3407 % o x,y,columns,rows: These values define the perimeter of a region of
3410 % o exception: return any errors or warnings in this structure.
3413 static const Quantum *GetVirtualPixelCache(const Image *image,
3414 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3415 const size_t columns,const size_t rows,ExceptionInfo *exception)
3421 id = GetOpenMPThreadId();
3426 assert(image != (const Image *) NULL);
3427 assert(image->signature == MagickSignature);
3428 assert(image->cache != (Cache) NULL);
3429 cache_info=(CacheInfo *) image->cache;
3430 assert(cache_info->signature == MagickSignature);
3431 assert(id < (int) cache_info->number_threads);
3432 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3433 cache_info->nexus_info[id],exception);
3438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3442 % G e t V i r t u a l P i x e l Q u e u e %
3446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3448 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3449 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3451 % The format of the GetVirtualPixelQueue() method is:
3453 % const Quantum *GetVirtualPixelQueue(const Image image)
3455 % A description of each parameter follows:
3457 % o image: the image.
3460 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3466 id = GetOpenMPThreadId();
3468 assert(image != (const Image *) NULL);
3469 assert(image->signature == MagickSignature);
3470 assert(image->cache != (Cache) NULL);
3471 cache_info=(CacheInfo *) image->cache;
3472 assert(cache_info->signature == MagickSignature);
3473 if (cache_info->methods.get_virtual_pixels_handler !=
3474 (GetVirtualPixelsHandler) NULL)
3475 return(cache_info->methods.get_virtual_pixels_handler(image));
3476 assert(id < (int) cache_info->number_threads);
3477 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3485 % G e t V i r t u a l P i x e l s %
3489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3491 % GetVirtualPixels() returns an immutable pixel region. If the
3492 % region is successfully accessed, a pointer to it is returned, otherwise
3493 % NULL is returned. The returned pointer may point to a temporary working
3494 % copy of the pixels or it may point to the original pixels in memory.
3495 % Performance is maximized if the selected region is part of one row, or one
3496 % or more full rows, since there is opportunity to access the pixels in-place
3497 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3498 % returned pointer must *never* be deallocated by the user.
3500 % Pixels accessed via the returned pointer represent a simple array of type
3501 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3502 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3503 % access the meta-content (of type void) corresponding to the the
3506 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3508 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3509 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3510 % GetCacheViewAuthenticPixels() instead.
3512 % The format of the GetVirtualPixels() method is:
3514 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3515 % const ssize_t y,const size_t columns,const size_t rows,
3516 % ExceptionInfo *exception)
3518 % A description of each parameter follows:
3520 % o image: the image.
3522 % o x,y,columns,rows: These values define the perimeter of a region of
3525 % o exception: return any errors or warnings in this structure.
3528 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3529 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3530 ExceptionInfo *exception)
3536 id = GetOpenMPThreadId();
3541 assert(image != (const Image *) NULL);
3542 assert(image->signature == MagickSignature);
3543 assert(image->cache != (Cache) NULL);
3544 cache_info=(CacheInfo *) image->cache;
3545 assert(cache_info->signature == MagickSignature);
3546 if (cache_info->methods.get_virtual_pixel_handler !=
3547 (GetVirtualPixelHandler) NULL)
3548 return(cache_info->methods.get_virtual_pixel_handler(image,
3549 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3550 assert(id < (int) cache_info->number_threads);
3551 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3552 columns,rows,cache_info->nexus_info[id],exception);
3557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3561 + G e t V i r t u a l P i x e l s F r o m C a c h e %
3565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3567 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3568 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3570 % The format of the GetVirtualPixelsCache() method is:
3572 % Quantum *GetVirtualPixelsCache(const Image *image)
3574 % A description of each parameter follows:
3576 % o image: the image.
3579 static const Quantum *GetVirtualPixelsCache(const Image *image)
3585 id = GetOpenMPThreadId();
3587 assert(image != (const Image *) NULL);
3588 assert(image->signature == MagickSignature);
3589 assert(image->cache != (Cache) NULL);
3590 cache_info=(CacheInfo *) image->cache;
3591 assert(cache_info->signature == MagickSignature);
3592 assert(id < (int) cache_info->number_threads);
3593 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3601 + G e t V i r t u a l P i x e l s N e x u s %
3605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3607 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3610 % The format of the GetVirtualPixelsNexus() method is:
3612 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3613 % NexusInfo *nexus_info)
3615 % A description of each parameter follows:
3617 % o cache: the pixel cache.
3619 % o nexus_info: the cache nexus to return the colormap pixels.
3622 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3623 NexusInfo *nexus_info)
3628 assert(cache != (Cache) NULL);
3629 cache_info=(CacheInfo *) cache;
3630 assert(cache_info->signature == MagickSignature);
3631 if (cache_info->storage_class == UndefinedClass)
3632 return((Quantum *) NULL);
3633 return((const Quantum *) nexus_info->pixels);
3637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3641 + O p e n P i x e l C a c h e %
3645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3648 % dimensions, allocating space for the image pixels and optionally the
3649 % metacontent, and memory mapping the cache if it is disk based. The cache
3650 % nexus array is initialized as well.
3652 % The format of the OpenPixelCache() method is:
3654 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3655 % ExceptionInfo *exception)
3657 % A description of each parameter follows:
3659 % o image: the image.
3661 % o mode: ReadMode, WriteMode, or IOMode.
3663 % o exception: return any errors or warnings in this structure.
3667 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3669 cache_info->mapped=MagickFalse;
3670 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3671 cache_info->length);
3672 if (cache_info->pixels == (Quantum *) NULL)
3674 cache_info->mapped=MagickTrue;
3675 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3676 cache_info->length);
3680 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3690 cache_info=(CacheInfo *) image->cache;
3691 if (image->debug != MagickFalse)
3694 format[MaxTextExtent],
3695 message[MaxTextExtent];
3697 (void) FormatMagickSize(length,MagickFalse,format);
3698 (void) FormatLocaleString(message,MaxTextExtent,
3699 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3700 cache_info->cache_filename,cache_info->file,format);
3701 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3703 if (length != (MagickSizeType) ((MagickOffsetType) length))
3704 return(MagickFalse);
3705 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3707 return(MagickFalse);
3708 if ((MagickSizeType) extent >= length)
3710 offset=(MagickOffsetType) length-1;
3711 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3712 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3715 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3716 ExceptionInfo *exception)
3723 format[MaxTextExtent],
3724 message[MaxTextExtent];
3741 assert(image != (const Image *) NULL);
3742 assert(image->signature == MagickSignature);
3743 assert(image->cache != (Cache) NULL);
3744 if (image->debug != MagickFalse)
3745 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3746 if ((image->columns == 0) || (image->rows == 0))
3747 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3748 cache_info=(CacheInfo *) image->cache;
3749 assert(cache_info->signature == MagickSignature);
3750 source_info=(*cache_info);
3751 source_info.file=(-1);
3752 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3753 image->filename,(double) GetImageIndexInList(image));
3754 cache_info->storage_class=image->storage_class;
3755 cache_info->colorspace=image->colorspace;
3756 cache_info->matte=image->matte;
3757 cache_info->mask=image->mask;
3758 cache_info->rows=image->rows;
3759 cache_info->columns=image->columns;
3760 InitializePixelChannelMap(image);
3761 cache_info->number_channels=GetPixelChannels(image);
3762 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3763 sizeof(*image->channel_map));
3764 cache_info->metacontent_extent=image->metacontent_extent;
3765 cache_info->mode=mode;
3766 if (image->ping != MagickFalse)
3768 cache_info->type=PingCache;
3769 cache_info->pixels=(Quantum *) NULL;
3770 cache_info->metacontent=(void *) NULL;
3771 cache_info->length=0;
3774 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3775 packet_size=cache_info->number_channels*sizeof(Quantum);
3776 if (image->metacontent_extent != 0)
3777 packet_size+=cache_info->metacontent_extent;
3778 length=number_pixels*packet_size;
3779 columns=(size_t) (length/cache_info->rows/packet_size);
3780 if (cache_info->columns != columns)
3781 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3783 cache_info->length=length;
3784 p=cache_info->channel_map;
3785 q=source_info.channel_map;
3786 if ((cache_info->type != UndefinedCache) &&
3787 (cache_info->columns <= source_info.columns) &&
3788 (cache_info->rows <= source_info.rows) &&
3789 (cache_info->number_channels <= source_info.number_channels) &&
3790 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
3791 (cache_info->metacontent_extent <= source_info.metacontent_extent))
3794 Inline pixel cache clone optimization.
3796 if ((cache_info->columns == source_info.columns) &&
3797 (cache_info->rows == source_info.rows) &&
3798 (cache_info->number_channels == source_info.number_channels) &&
3799 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
3800 (cache_info->metacontent_extent == source_info.metacontent_extent))
3802 return(ClonePixelCachePixels(cache_info,&source_info,exception));
3804 status=AcquireMagickResource(AreaResource,cache_info->length);
3805 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3806 cache_info->metacontent_extent);
3807 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3809 status=AcquireMagickResource(MemoryResource,cache_info->length);
3810 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3811 (cache_info->type == MemoryCache))
3813 AllocatePixelCachePixels(cache_info);
3814 if (cache_info->pixels == (Quantum *) NULL)
3815 cache_info->pixels=source_info.pixels;
3819 Create memory pixel cache.
3822 if (image->debug != MagickFalse)
3824 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3825 (void) FormatLocaleString(message,MaxTextExtent,
3826 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3827 cache_info->filename,cache_info->mapped != MagickFalse ?
3828 "anonymous" : "heap",(double) cache_info->columns,(double)
3829 cache_info->rows,(double) cache_info->number_channels,
3831 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3834 cache_info->type=MemoryCache;
3835 cache_info->metacontent=(void *) NULL;
3836 if (cache_info->metacontent_extent != 0)
3837 cache_info->metacontent=(void *) (cache_info->pixels+
3838 number_pixels*cache_info->number_channels);
3839 if ((source_info.storage_class != UndefinedClass) &&
3842 status=ClonePixelCachePixels(cache_info,&source_info,
3844 RelinquishPixelCachePixels(&source_info);
3849 RelinquishMagickResource(MemoryResource,cache_info->length);
3852 Create pixel cache on disk.
3854 status=AcquireMagickResource(DiskResource,cache_info->length);
3855 if (status == MagickFalse)
3857 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3858 "CacheResourcesExhausted","`%s'",image->filename);
3859 return(MagickFalse);
3861 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3863 (void) ClosePixelCacheOnDisk(cache_info);
3864 *cache_info->cache_filename='\0';
3866 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3868 RelinquishMagickResource(DiskResource,cache_info->length);
3869 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3871 return(MagickFalse);
3873 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
3874 cache_info->length);
3875 if (status == MagickFalse)
3877 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3879 return(MagickFalse);
3881 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3882 cache_info->metacontent_extent);
3883 if (length != (MagickSizeType) ((size_t) length))
3884 cache_info->type=DiskCache;
3887 status=AcquireMagickResource(MapResource,cache_info->length);
3888 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3889 (cache_info->type != MemoryCache))
3890 cache_info->type=DiskCache;
3893 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3894 cache_info->offset,(size_t) cache_info->length);
3895 if (cache_info->pixels == (Quantum *) NULL)
3897 cache_info->type=DiskCache;
3898 cache_info->pixels=source_info.pixels;
3903 Create file-backed memory-mapped pixel cache.
3906 (void) ClosePixelCacheOnDisk(cache_info);
3907 cache_info->type=MapCache;
3908 cache_info->mapped=MagickTrue;
3909 cache_info->metacontent=(void *) NULL;
3910 if (cache_info->metacontent_extent != 0)
3911 cache_info->metacontent=(void *) (cache_info->pixels+
3912 number_pixels*cache_info->number_channels);
3913 if ((source_info.storage_class != UndefinedClass) &&
3916 status=ClonePixelCachePixels(cache_info,&source_info,
3918 RelinquishPixelCachePixels(&source_info);
3920 if (image->debug != MagickFalse)
3922 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3923 (void) FormatLocaleString(message,MaxTextExtent,
3924 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
3925 cache_info->filename,cache_info->cache_filename,
3926 cache_info->file,(double) cache_info->columns,(double)
3927 cache_info->rows,(double) cache_info->number_channels,
3929 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3935 RelinquishMagickResource(MapResource,cache_info->length);
3938 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3940 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3941 RelinquishPixelCachePixels(&source_info);
3943 if (image->debug != MagickFalse)
3945 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3946 (void) FormatLocaleString(message,MaxTextExtent,
3947 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
3948 cache_info->cache_filename,cache_info->file,(double)
3949 cache_info->columns,(double) cache_info->rows,(double)
3950 cache_info->number_channels,format);
3951 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3961 + P e r s i s t P i x e l C a c h e %
3965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3967 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3968 % persistent pixel cache is one that resides on disk and is not destroyed
3969 % when the program exits.
3971 % The format of the PersistPixelCache() method is:
3973 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3974 % const MagickBooleanType attach,MagickOffsetType *offset,
3975 % ExceptionInfo *exception)
3977 % A description of each parameter follows:
3979 % o image: the image.
3981 % o filename: the persistent pixel cache filename.
3983 % o attach: A value other than zero initializes the persistent pixel cache.
3985 % o initialize: A value other than zero initializes the persistent pixel
3988 % o offset: the offset in the persistent cache to store pixels.
3990 % o exception: return any errors or warnings in this structure.
3993 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3994 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3995 ExceptionInfo *exception)
4010 assert(image != (Image *) NULL);
4011 assert(image->signature == MagickSignature);
4012 if (image->debug != MagickFalse)
4013 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4014 assert(image->cache != (void *) NULL);
4015 assert(filename != (const char *) NULL);
4016 assert(offset != (MagickOffsetType *) NULL);
4017 page_size=GetMagickPageSize();
4018 cache_info=(CacheInfo *) image->cache;
4019 assert(cache_info->signature == MagickSignature);
4020 if (attach != MagickFalse)
4023 Attach existing persistent pixel cache.
4025 if (image->debug != MagickFalse)
4026 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4027 "attach persistent cache");
4028 (void) CopyMagickString(cache_info->cache_filename,filename,
4030 cache_info->type=DiskCache;
4031 cache_info->offset=(*offset);
4032 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4033 return(MagickFalse);
4034 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4037 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4038 (cache_info->reference_count == 1))
4040 LockSemaphoreInfo(cache_info->semaphore);
4041 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4042 (cache_info->reference_count == 1))
4048 Usurp existing persistent pixel cache.
4050 status=rename_utf8(cache_info->cache_filename,filename);
4053 (void) CopyMagickString(cache_info->cache_filename,filename,
4055 *offset+=cache_info->length+page_size-(cache_info->length %
4057 UnlockSemaphoreInfo(cache_info->semaphore);
4058 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4059 if (image->debug != MagickFalse)
4060 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4061 "Usurp resident persistent cache");
4065 UnlockSemaphoreInfo(cache_info->semaphore);
4068 Clone persistent pixel cache.
4070 clone_image=(*image);
4071 clone_info=(CacheInfo *) clone_image.cache;
4072 image->cache=ClonePixelCache(cache_info);
4073 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4074 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4075 cache_info->type=DiskCache;
4076 cache_info->offset=(*offset);
4077 cache_info=(CacheInfo *) image->cache;
4078 status=OpenPixelCache(image,IOMode,exception);
4079 if (status != MagickFalse)
4080 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4081 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4082 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4087 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4091 + 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 %
4095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4097 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4098 % defined by the region rectangle and returns a pointer to the region. This
4099 % region is subsequently transferred from the pixel cache with
4100 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4101 % pixels are transferred, otherwise a NULL is returned.
4103 % The format of the QueueAuthenticPixelCacheNexus() method is:
4105 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4106 % const ssize_t y,const size_t columns,const size_t rows,
4107 % const MagickBooleanType clone,NexusInfo *nexus_info,
4108 % ExceptionInfo *exception)
4110 % A description of each parameter follows:
4112 % o image: the image.
4114 % o x,y,columns,rows: These values define the perimeter of a region of
4117 % o nexus_info: the cache nexus to set.
4119 % o clone: clone the pixel cache.
4121 % o exception: return any errors or warnings in this structure.
4124 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4125 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4126 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4141 Validate pixel cache geometry.
4143 assert(image != (const Image *) NULL);
4144 assert(image->signature == MagickSignature);
4145 assert(image->cache != (Cache) NULL);
4146 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4147 if (cache_info == (Cache) NULL)
4148 return((Quantum *) NULL);
4149 assert(cache_info->signature == MagickSignature);
4150 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4152 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4153 "NoPixelsDefinedInCache","`%s'",image->filename);
4154 return((Quantum *) NULL);
4156 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4157 (y >= (ssize_t) cache_info->rows))
4159 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4160 "PixelsAreNotAuthentic","`%s'",image->filename);
4161 return((Quantum *) NULL);
4163 offset=(MagickOffsetType) y*cache_info->columns+x;
4165 return((Quantum *) NULL);
4166 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4167 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4168 if ((MagickSizeType) offset >= number_pixels)
4169 return((Quantum *) NULL);
4175 region.width=columns;
4177 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4185 + 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 %
4189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4191 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4192 % defined by the region rectangle and returns a pointer to the region. This
4193 % region is subsequently transferred from the pixel cache with
4194 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4195 % pixels are transferred, otherwise a NULL is returned.
4197 % The format of the QueueAuthenticPixelsCache() method is:
4199 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4200 % const ssize_t y,const size_t columns,const size_t rows,
4201 % ExceptionInfo *exception)
4203 % A description of each parameter follows:
4205 % o image: the image.
4207 % o x,y,columns,rows: These values define the perimeter of a region of
4210 % o exception: return any errors or warnings in this structure.
4213 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4214 const ssize_t y,const size_t columns,const size_t rows,
4215 ExceptionInfo *exception)
4221 id = GetOpenMPThreadId();
4226 assert(image != (const Image *) NULL);
4227 assert(image->signature == MagickSignature);
4228 assert(image->cache != (Cache) NULL);
4229 cache_info=(CacheInfo *) image->cache;
4230 assert(cache_info->signature == MagickSignature);
4231 assert(id < (int) cache_info->number_threads);
4232 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4233 cache_info->nexus_info[id],exception);
4238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4242 % Q u e u e A u t h e n t i c P i x e l s %
4246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4248 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4249 % successfully initialized a pointer to a Quantum array representing the
4250 % region is returned, otherwise NULL is returned. The returned pointer may
4251 % point to a temporary working buffer for the pixels or it may point to the
4252 % final location of the pixels in memory.
4254 % Write-only access means that any existing pixel values corresponding to
4255 % the region are ignored. This is useful if the initial image is being
4256 % created from scratch, or if the existing pixel values are to be
4257 % completely replaced without need to refer to their pre-existing values.
4258 % The application is free to read and write the pixel buffer returned by
4259 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4260 % initialize the pixel array values. Initializing pixel array values is the
4261 % application's responsibility.
4263 % Performance is maximized if the selected region is part of one row, or
4264 % one or more full rows, since then there is opportunity to access the
4265 % pixels in-place (without a copy) if the image is in memory, or in a
4266 % memory-mapped file. The returned pointer must *never* be deallocated
4269 % Pixels accessed via the returned pointer represent a simple array of type
4270 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4271 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4272 % obtain the meta-content (of type void) corresponding to the region.
4273 % Once the Quantum (and/or Quantum) array has been updated, the
4274 % changes must be saved back to the underlying image using
4275 % SyncAuthenticPixels() or they may be lost.
4277 % The format of the QueueAuthenticPixels() method is:
4279 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4280 % const ssize_t y,const size_t columns,const size_t rows,
4281 % ExceptionInfo *exception)
4283 % A description of each parameter follows:
4285 % o image: the image.
4287 % o x,y,columns,rows: These values define the perimeter of a region of
4290 % o exception: return any errors or warnings in this structure.
4293 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4294 const ssize_t y,const size_t columns,const size_t rows,
4295 ExceptionInfo *exception)
4301 id = GetOpenMPThreadId();
4306 assert(image != (Image *) NULL);
4307 assert(image->signature == MagickSignature);
4308 assert(image->cache != (Cache) NULL);
4309 cache_info=(CacheInfo *) image->cache;
4310 assert(cache_info->signature == MagickSignature);
4311 if (cache_info->methods.queue_authentic_pixels_handler !=
4312 (QueueAuthenticPixelsHandler) NULL)
4314 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4315 columns,rows,exception);
4318 assert(id < (int) cache_info->number_threads);
4319 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4320 cache_info->nexus_info[id],exception);
4325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4329 + 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 %
4333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4335 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4338 % The format of the ReadPixelCacheMetacontent() method is:
4340 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4341 % NexusInfo *nexus_info,ExceptionInfo *exception)
4343 % A description of each parameter follows:
4345 % o cache_info: the pixel cache.
4347 % o nexus_info: the cache nexus to read the metacontent.
4349 % o exception: return any errors or warnings in this structure.
4352 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4353 NexusInfo *nexus_info,ExceptionInfo *exception)
4366 register unsigned char
4372 if (cache_info->metacontent_extent == 0)
4373 return(MagickFalse);
4374 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4376 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4377 nexus_info->region.x;
4378 length=(MagickSizeType) nexus_info->region.width*
4379 cache_info->metacontent_extent;
4380 rows=nexus_info->region.height;
4382 q=(unsigned char *) nexus_info->metacontent;
4383 switch (cache_info->type)
4388 register unsigned char
4392 Read meta-content from memory.
4394 if ((cache_info->columns == nexus_info->region.width) &&
4395 (extent == (MagickSizeType) ((size_t) extent)))
4400 p=(unsigned char *) cache_info->metacontent+offset*
4401 cache_info->metacontent_extent;
4402 for (y=0; y < (ssize_t) rows; y++)
4404 (void) memcpy(q,p,(size_t) length);
4405 p+=cache_info->metacontent_extent*cache_info->columns;
4406 q+=cache_info->metacontent_extent*nexus_info->region.width;
4413 Read meta content from disk.
4415 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4417 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4418 cache_info->cache_filename);
4419 return(MagickFalse);
4421 if ((cache_info->columns == nexus_info->region.width) &&
4422 (extent <= MagickMaxBufferExtent))
4427 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4428 for (y=0; y < (ssize_t) rows; y++)
4430 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4431 cache_info->number_channels*sizeof(Quantum)+offset*
4432 cache_info->metacontent_extent,length,(unsigned char *) q);
4433 if ((MagickSizeType) count != length)
4435 offset+=cache_info->columns;
4436 q+=cache_info->metacontent_extent*nexus_info->region.width;
4438 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4439 (void) ClosePixelCacheOnDisk(cache_info);
4440 if (y < (ssize_t) rows)
4442 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4443 cache_info->cache_filename);
4444 return(MagickFalse);
4451 if ((cache_info->debug != MagickFalse) &&
4452 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4453 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4454 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4455 nexus_info->region.width,(double) nexus_info->region.height,(double)
4456 nexus_info->region.x,(double) nexus_info->region.y);
4461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4465 + R e a d P i x e l C a c h e P i x e l s %
4469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4471 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4474 % The format of the ReadPixelCachePixels() method is:
4476 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4477 % NexusInfo *nexus_info,ExceptionInfo *exception)
4479 % A description of each parameter follows:
4481 % o cache_info: the pixel cache.
4483 % o nexus_info: the cache nexus to read the pixels.
4485 % o exception: return any errors or warnings in this structure.
4488 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4489 NexusInfo *nexus_info,ExceptionInfo *exception)
4508 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4510 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4511 nexus_info->region.x;
4512 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4514 rows=nexus_info->region.height;
4516 q=nexus_info->pixels;
4517 switch (cache_info->type)
4526 Read pixels from memory.
4528 if ((cache_info->columns == nexus_info->region.width) &&
4529 (extent == (MagickSizeType) ((size_t) extent)))
4534 p=cache_info->pixels+offset*cache_info->number_channels;
4535 for (y=0; y < (ssize_t) rows; y++)
4537 (void) memcpy(q,p,(size_t) length);
4538 p+=cache_info->number_channels*cache_info->columns;
4539 q+=cache_info->number_channels*nexus_info->region.width;
4546 Read pixels from disk.
4548 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4550 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4551 cache_info->cache_filename);
4552 return(MagickFalse);
4554 if ((cache_info->columns == nexus_info->region.width) &&
4555 (extent <= MagickMaxBufferExtent))
4560 for (y=0; y < (ssize_t) rows; y++)
4562 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4563 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4564 if ((MagickSizeType) count != length)
4566 offset+=cache_info->columns;
4567 q+=cache_info->number_channels*nexus_info->region.width;
4569 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4570 (void) ClosePixelCacheOnDisk(cache_info);
4571 if (y < (ssize_t) rows)
4573 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4574 cache_info->cache_filename);
4575 return(MagickFalse);
4582 if ((cache_info->debug != MagickFalse) &&
4583 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4584 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4585 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4586 nexus_info->region.width,(double) nexus_info->region.height,(double)
4587 nexus_info->region.x,(double) nexus_info->region.y);
4592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4596 + R e f e r e n c e P i x e l C a c h e %
4600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4602 % ReferencePixelCache() increments the reference count associated with the
4603 % pixel cache returning a pointer to the cache.
4605 % The format of the ReferencePixelCache method is:
4607 % Cache ReferencePixelCache(Cache cache_info)
4609 % A description of each parameter follows:
4611 % o cache_info: the pixel cache.
4614 MagickPrivate Cache ReferencePixelCache(Cache cache)
4619 assert(cache != (Cache *) NULL);
4620 cache_info=(CacheInfo *) cache;
4621 assert(cache_info->signature == MagickSignature);
4622 LockSemaphoreInfo(cache_info->semaphore);
4623 cache_info->reference_count++;
4624 UnlockSemaphoreInfo(cache_info->semaphore);
4629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4633 + S e t P i x e l C a c h e M e t h o d s %
4637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4639 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4641 % The format of the SetPixelCacheMethods() method is:
4643 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4645 % A description of each parameter follows:
4647 % o cache: the pixel cache.
4649 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4652 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4657 GetOneAuthenticPixelFromHandler
4658 get_one_authentic_pixel_from_handler;
4660 GetOneVirtualPixelFromHandler
4661 get_one_virtual_pixel_from_handler;
4664 Set cache pixel methods.
4666 assert(cache != (Cache) NULL);
4667 assert(cache_methods != (CacheMethods *) NULL);
4668 cache_info=(CacheInfo *) cache;
4669 assert(cache_info->signature == MagickSignature);
4670 if (cache_info->debug != MagickFalse)
4671 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4672 cache_info->filename);
4673 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4674 cache_info->methods.get_virtual_pixel_handler=
4675 cache_methods->get_virtual_pixel_handler;
4676 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4677 cache_info->methods.destroy_pixel_handler=
4678 cache_methods->destroy_pixel_handler;
4679 if (cache_methods->get_virtual_metacontent_from_handler !=
4680 (GetVirtualMetacontentFromHandler) NULL)
4681 cache_info->methods.get_virtual_metacontent_from_handler=
4682 cache_methods->get_virtual_metacontent_from_handler;
4683 if (cache_methods->get_authentic_pixels_handler !=
4684 (GetAuthenticPixelsHandler) NULL)
4685 cache_info->methods.get_authentic_pixels_handler=
4686 cache_methods->get_authentic_pixels_handler;
4687 if (cache_methods->queue_authentic_pixels_handler !=
4688 (QueueAuthenticPixelsHandler) NULL)
4689 cache_info->methods.queue_authentic_pixels_handler=
4690 cache_methods->queue_authentic_pixels_handler;
4691 if (cache_methods->sync_authentic_pixels_handler !=
4692 (SyncAuthenticPixelsHandler) NULL)
4693 cache_info->methods.sync_authentic_pixels_handler=
4694 cache_methods->sync_authentic_pixels_handler;
4695 if (cache_methods->get_authentic_pixels_from_handler !=
4696 (GetAuthenticPixelsFromHandler) NULL)
4697 cache_info->methods.get_authentic_pixels_from_handler=
4698 cache_methods->get_authentic_pixels_from_handler;
4699 if (cache_methods->get_authentic_metacontent_from_handler !=
4700 (GetAuthenticMetacontentFromHandler) NULL)
4701 cache_info->methods.get_authentic_metacontent_from_handler=
4702 cache_methods->get_authentic_metacontent_from_handler;
4703 get_one_virtual_pixel_from_handler=
4704 cache_info->methods.get_one_virtual_pixel_from_handler;
4705 if (get_one_virtual_pixel_from_handler !=
4706 (GetOneVirtualPixelFromHandler) NULL)
4707 cache_info->methods.get_one_virtual_pixel_from_handler=
4708 cache_methods->get_one_virtual_pixel_from_handler;
4709 get_one_authentic_pixel_from_handler=
4710 cache_methods->get_one_authentic_pixel_from_handler;
4711 if (get_one_authentic_pixel_from_handler !=
4712 (GetOneAuthenticPixelFromHandler) NULL)
4713 cache_info->methods.get_one_authentic_pixel_from_handler=
4714 cache_methods->get_one_authentic_pixel_from_handler;
4718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4722 + S e t P i x e l C a c h e N e x u s P i x e l s %
4726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4728 % SetPixelCacheNexusPixels() defines the region of the cache for the
4729 % specified cache nexus.
4731 % The format of the SetPixelCacheNexusPixels() method is:
4733 % Quantum SetPixelCacheNexusPixels(const Image *image,
4734 % const RectangleInfo *region,NexusInfo *nexus_info,
4735 % ExceptionInfo *exception)
4737 % A description of each parameter follows:
4739 % o image: the image.
4741 % o region: A pointer to the RectangleInfo structure that defines the
4742 % region of this particular cache nexus.
4744 % o nexus_info: the cache nexus to set.
4746 % o exception: return any errors or warnings in this structure.
4750 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4751 NexusInfo *nexus_info,ExceptionInfo *exception)
4753 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4754 return(MagickFalse);
4755 nexus_info->mapped=MagickFalse;
4756 nexus_info->cache=(Quantum *) AcquireAlignedMemory(1,(size_t)
4757 nexus_info->length);
4758 if (nexus_info->cache == (Quantum *) NULL)
4760 nexus_info->mapped=MagickTrue;
4761 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4762 nexus_info->length);
4764 if (nexus_info->cache == (Quantum *) NULL)
4766 (void) ThrowMagickException(exception,GetMagickModule(),
4767 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4768 cache_info->filename);
4769 return(MagickFalse);
4774 static Quantum *SetPixelCacheNexusPixels(const Image *image,
4775 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4787 cache_info=(CacheInfo *) image->cache;
4788 assert(cache_info->signature == MagickSignature);
4789 if (cache_info->type == UndefinedCache)
4790 return((Quantum *) NULL);
4791 nexus_info->region=(*region);
4792 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
4798 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4799 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4800 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4801 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4802 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4803 ((nexus_info->region.width == cache_info->columns) ||
4804 ((nexus_info->region.width % cache_info->columns) == 0)))))
4810 Pixels are accessed directly from memory.
4812 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4813 nexus_info->region.x;
4814 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4816 nexus_info->metacontent=(void *) NULL;
4817 if (cache_info->metacontent_extent != 0)
4818 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4819 offset*cache_info->metacontent_extent;
4820 return(nexus_info->pixels);
4824 Pixels are stored in a cache region until they are synced to the cache.
4826 number_pixels=(MagickSizeType) nexus_info->region.width*
4827 nexus_info->region.height;
4828 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4829 if (cache_info->metacontent_extent != 0)
4830 length+=number_pixels*cache_info->metacontent_extent;
4831 if (nexus_info->cache == (Quantum *) NULL)
4833 nexus_info->length=length;
4834 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4835 if (status == MagickFalse)
4837 nexus_info->length=0;
4838 return((Quantum *) NULL);
4842 if (nexus_info->length != length)
4844 RelinquishCacheNexusPixels(nexus_info);
4845 nexus_info->length=length;
4846 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4847 if (status == MagickFalse)
4849 nexus_info->length=0;
4850 return((Quantum *) NULL);
4853 nexus_info->pixels=nexus_info->cache;
4854 nexus_info->metacontent=(void *) NULL;
4855 if (cache_info->metacontent_extent != 0)
4856 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4857 cache_info->number_channels);
4858 return(nexus_info->pixels);
4862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4866 % 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 %
4870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4872 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4873 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4874 % access that is outside the boundaries of the image cache.
4876 % The format of the SetPixelCacheVirtualMethod() method is:
4878 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4879 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4881 % A description of each parameter follows:
4883 % o image: the image.
4885 % o virtual_pixel_method: choose the type of virtual pixel.
4887 % o exception: return any errors or warnings in this structure.
4891 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4892 ExceptionInfo *exception)
4903 assert(image != (Image *) NULL);
4904 assert(image->signature == MagickSignature);
4905 if (image->debug != MagickFalse)
4906 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4907 assert(image->cache != (Cache) NULL);
4908 cache_info=(CacheInfo *) image->cache;
4909 assert(cache_info->signature == MagickSignature);
4910 image->matte=MagickTrue;
4912 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4913 #pragma omp parallel for schedule(static,4) shared(status)
4915 for (y=0; y < (ssize_t) image->rows; y++)
4918 id = GetOpenMPThreadId();
4926 if (status == MagickFalse)
4928 q=GetAuthenticPixelCacheNexus(image,0,y,image->columns,1,
4929 cache_info->nexus_info[id],exception);
4930 if (q == (Quantum *) NULL)
4935 for (x=0; x < (ssize_t) image->columns; x++)
4937 SetPixelAlpha(image,alpha,q);
4938 q+=GetPixelChannels(image);
4940 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
4946 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4947 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4955 assert(image != (Image *) NULL);
4956 assert(image->signature == MagickSignature);
4957 if (image->debug != MagickFalse)
4958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4959 assert(image->cache != (Cache) NULL);
4960 cache_info=(CacheInfo *) image->cache;
4961 assert(cache_info->signature == MagickSignature);
4962 method=cache_info->virtual_pixel_method;
4963 cache_info->virtual_pixel_method=virtual_pixel_method;
4964 switch (virtual_pixel_method)
4966 case BackgroundVirtualPixelMethod:
4968 if ((image->background_color.matte != MagickFalse) &&
4969 (image->matte == MagickFalse))
4970 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4973 case TransparentVirtualPixelMethod:
4975 if (image->matte == MagickFalse)
4976 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4990 + 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 %
4994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4996 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
4997 % in-memory or disk cache. The method returns MagickTrue if the pixel region
4998 % is synced, otherwise MagickFalse.
5000 % The format of the SyncAuthenticPixelCacheNexus() method is:
5002 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5003 % NexusInfo *nexus_info,ExceptionInfo *exception)
5005 % A description of each parameter follows:
5007 % o image: the image.
5009 % o nexus_info: the cache nexus to sync.
5011 % o exception: return any errors or warnings in this structure.
5014 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5015 NexusInfo *nexus_info,ExceptionInfo *exception)
5024 Transfer pixels to the cache.
5026 assert(image != (Image *) NULL);
5027 assert(image->signature == MagickSignature);
5028 if (image->cache == (Cache) NULL)
5029 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5030 cache_info=(CacheInfo *) image->cache;
5031 assert(cache_info->signature == MagickSignature);
5032 if (cache_info->type == UndefinedCache)
5033 return(MagickFalse);
5034 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5036 assert(cache_info->signature == MagickSignature);
5037 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5038 if ((cache_info->metacontent_extent != 0) &&
5039 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5040 return(MagickFalse);
5045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5049 + S y n c A u t h e n t i c P i x e l C a c h e %
5053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5055 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5056 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5057 % otherwise MagickFalse.
5059 % The format of the SyncAuthenticPixelsCache() method is:
5061 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5062 % ExceptionInfo *exception)
5064 % A description of each parameter follows:
5066 % o image: the image.
5068 % o exception: return any errors or warnings in this structure.
5071 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5072 ExceptionInfo *exception)
5078 id = GetOpenMPThreadId();
5083 assert(image != (Image *) NULL);
5084 assert(image->signature == MagickSignature);
5085 assert(image->cache != (Cache) NULL);
5086 cache_info=(CacheInfo *) image->cache;
5087 assert(cache_info->signature == MagickSignature);
5088 assert(id < (int) cache_info->number_threads);
5089 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5099 % S y n c A u t h e n t i c P i x e l s %
5103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5105 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5106 % The method returns MagickTrue if the pixel region is flushed, otherwise
5109 % The format of the SyncAuthenticPixels() method is:
5111 % MagickBooleanType SyncAuthenticPixels(Image *image,
5112 % ExceptionInfo *exception)
5114 % A description of each parameter follows:
5116 % o image: the image.
5118 % o exception: return any errors or warnings in this structure.
5121 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5122 ExceptionInfo *exception)
5128 id = GetOpenMPThreadId();
5133 assert(image != (Image *) NULL);
5134 assert(image->signature == MagickSignature);
5135 assert(image->cache != (Cache) NULL);
5136 cache_info=(CacheInfo *) image->cache;
5137 assert(cache_info->signature == MagickSignature);
5138 if (cache_info->methods.sync_authentic_pixels_handler !=
5139 (SyncAuthenticPixelsHandler) NULL)
5141 status=cache_info->methods.sync_authentic_pixels_handler(image,
5145 assert(id < (int) cache_info->number_threads);
5146 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5156 + S y n c I m a g e P i x e l C a c h e %
5160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5162 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5163 % The method returns MagickTrue if the pixel region is flushed, otherwise
5166 % The format of the SyncImagePixelCache() method is:
5168 % MagickBooleanType SyncImagePixelCache(Image *image,
5169 % ExceptionInfo *exception)
5171 % A description of each parameter follows:
5173 % o image: the image.
5175 % o exception: return any errors or warnings in this structure.
5178 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5179 ExceptionInfo *exception)
5184 assert(image != (Image *) NULL);
5185 assert(exception != (ExceptionInfo *) NULL);
5186 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5187 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5195 + 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 %
5199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5201 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5202 % of the pixel cache.
5204 % The format of the WritePixelCacheMetacontent() method is:
5206 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5207 % NexusInfo *nexus_info,ExceptionInfo *exception)
5209 % A description of each parameter follows:
5211 % o cache_info: the pixel cache.
5213 % o nexus_info: the cache nexus to write the meta-content.
5215 % o exception: return any errors or warnings in this structure.
5218 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5219 NexusInfo *nexus_info,ExceptionInfo *exception)
5229 register const unsigned char
5238 if (cache_info->metacontent_extent == 0)
5239 return(MagickFalse);
5240 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5242 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5243 nexus_info->region.x;
5244 length=(MagickSizeType) nexus_info->region.width*
5245 cache_info->metacontent_extent;
5246 rows=nexus_info->region.height;
5247 extent=(MagickSizeType) length*rows;
5248 p=(unsigned char *) nexus_info->metacontent;
5249 switch (cache_info->type)
5254 register unsigned char
5258 Write associated pixels to memory.
5260 if ((cache_info->columns == nexus_info->region.width) &&
5261 (extent == (MagickSizeType) ((size_t) extent)))
5266 q=(unsigned char *) cache_info->metacontent+offset*
5267 cache_info->metacontent_extent;
5268 for (y=0; y < (ssize_t) rows; y++)
5270 (void) memcpy(q,p,(size_t) length);
5271 p+=nexus_info->region.width*cache_info->metacontent_extent;
5272 q+=cache_info->columns*cache_info->metacontent_extent;
5279 Write associated pixels to disk.
5281 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5283 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5284 cache_info->cache_filename);
5285 return(MagickFalse);
5287 if ((cache_info->columns == nexus_info->region.width) &&
5288 (extent <= MagickMaxBufferExtent))
5293 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5294 for (y=0; y < (ssize_t) rows; y++)
5296 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5297 cache_info->number_channels*sizeof(Quantum)+offset*
5298 cache_info->metacontent_extent,length,(const unsigned char *) p);
5299 if ((MagickSizeType) count != length)
5301 p+=nexus_info->region.width*cache_info->metacontent_extent;
5302 offset+=cache_info->columns;
5304 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5305 (void) ClosePixelCacheOnDisk(cache_info);
5306 if (y < (ssize_t) rows)
5308 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5309 cache_info->cache_filename);
5310 return(MagickFalse);
5317 if ((cache_info->debug != MagickFalse) &&
5318 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5319 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5320 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5321 nexus_info->region.width,(double) nexus_info->region.height,(double)
5322 nexus_info->region.x,(double) nexus_info->region.y);
5327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5331 + W r i t e C a c h e P i x e l s %
5335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5337 % WritePixelCachePixels() writes image pixels to the specified region of the
5340 % The format of the WritePixelCachePixels() method is:
5342 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5343 % NexusInfo *nexus_info,ExceptionInfo *exception)
5345 % A description of each parameter follows:
5347 % o cache_info: the pixel cache.
5349 % o nexus_info: the cache nexus to write the pixels.
5351 % o exception: return any errors or warnings in this structure.
5354 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5355 NexusInfo *nexus_info,ExceptionInfo *exception)
5365 register const Quantum
5374 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5376 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5377 nexus_info->region.x;
5378 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5380 rows=nexus_info->region.height;
5382 p=nexus_info->pixels;
5383 switch (cache_info->type)
5392 Write pixels to memory.
5394 if ((cache_info->columns == nexus_info->region.width) &&
5395 (extent == (MagickSizeType) ((size_t) extent)))
5400 q=cache_info->pixels+offset*cache_info->number_channels;
5401 for (y=0; y < (ssize_t) rows; y++)
5403 (void) memcpy(q,p,(size_t) length);
5404 p+=nexus_info->region.width*cache_info->number_channels;
5405 q+=cache_info->columns*cache_info->number_channels;
5412 Write pixels to disk.
5414 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5416 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5417 cache_info->cache_filename);
5418 return(MagickFalse);
5420 if ((cache_info->columns == nexus_info->region.width) &&
5421 (extent <= MagickMaxBufferExtent))
5426 for (y=0; y < (ssize_t) rows; y++)
5428 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5429 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5431 if ((MagickSizeType) count != length)
5433 p+=nexus_info->region.width*cache_info->number_channels;
5434 offset+=cache_info->columns;
5436 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5437 (void) ClosePixelCacheOnDisk(cache_info);
5438 if (y < (ssize_t) rows)
5440 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5441 cache_info->cache_filename);
5442 return(MagickFalse);
5449 if ((cache_info->debug != MagickFalse) &&
5450 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5451 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5452 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5453 nexus_info->region.width,(double) nexus_info->region.height,(double)
5454 nexus_info->region.x,(double) nexus_info->region.y);