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-2013 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/composite-private.h"
51 #include "MagickCore/exception.h"
52 #include "MagickCore/exception-private.h"
53 #include "MagickCore/geometry.h"
54 #include "MagickCore/list.h"
55 #include "MagickCore/log.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/memory-private.h"
59 #include "MagickCore/nt-base-private.h"
60 #include "MagickCore/pixel.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/policy.h"
63 #include "MagickCore/quantum.h"
64 #include "MagickCore/random_.h"
65 #include "MagickCore/registry.h"
66 #include "MagickCore/resource_.h"
67 #include "MagickCore/semaphore.h"
68 #include "MagickCore/splay-tree.h"
69 #include "MagickCore/string_.h"
70 #include "MagickCore/string-private.h"
71 #include "MagickCore/thread-private.h"
72 #include "MagickCore/utility.h"
73 #include "MagickCore/utility-private.h"
74 #if defined(MAGICKCORE_ZLIB_DELEGATE)
81 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
82 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
83 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
88 typedef struct _MagickModulo
118 Forward declarations.
120 #if defined(__cplusplus) || defined(c_plusplus)
125 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
129 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
130 const ssize_t,const size_t,const size_t,ExceptionInfo *),
131 *GetVirtualPixelsCache(const Image *);
134 *GetVirtualMetacontentFromCache(const Image *);
136 static MagickBooleanType
137 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
139 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
140 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
141 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
142 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
143 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
144 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
145 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
146 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
149 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
150 const size_t,ExceptionInfo *),
151 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
152 const size_t,ExceptionInfo *),
153 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
154 NexusInfo *,ExceptionInfo *) magick_hot_spot;
156 #if defined(__cplusplus) || defined(c_plusplus)
163 static volatile MagickBooleanType
164 instantiate_cache = MagickFalse;
167 *cache_semaphore = (SemaphoreInfo *) NULL;
170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
174 + A c q u i r e P i x e l C a c h e %
178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180 % AcquirePixelCache() acquires a pixel cache.
182 % The format of the AcquirePixelCache() method is:
184 % Cache AcquirePixelCache(const size_t number_threads)
186 % A description of each parameter follows:
188 % o number_threads: the number of nexus threads.
191 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
199 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
200 if (cache_info == (CacheInfo *) NULL)
201 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
202 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
203 cache_info->type=UndefinedCache;
204 cache_info->mode=IOMode;
205 cache_info->colorspace=sRGBColorspace;
206 cache_info->file=(-1);
207 cache_info->id=GetMagickThreadId();
208 cache_info->number_threads=number_threads;
209 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
210 cache_info->number_threads=GetOpenMPMaximumThreads();
211 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
212 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
213 if (cache_info->number_threads == 0)
214 cache_info->number_threads=1;
215 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
216 if (cache_info->nexus_info == (NexusInfo **) NULL)
217 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
218 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
219 if (synchronize != (const char *) NULL)
221 cache_info->synchronize=IsStringTrue(synchronize);
222 synchronize=DestroyString(synchronize);
224 cache_info->semaphore=AllocateSemaphoreInfo();
225 cache_info->reference_count=1;
226 cache_info->file_semaphore=AllocateSemaphoreInfo();
227 cache_info->debug=IsEventLogging();
228 cache_info->signature=MagickSignature;
229 return((Cache ) cache_info);
233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 % A c q u i r e P i x e l C a c h e N e x u s %
241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
243 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
245 % The format of the AcquirePixelCacheNexus method is:
247 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
249 % A description of each parameter follows:
251 % o number_threads: the number of nexus threads.
254 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
262 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
263 number_threads,sizeof(*nexus_info)));
264 if (nexus_info == (NexusInfo **) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
267 sizeof(**nexus_info));
268 if (nexus_info[0] == (NexusInfo *) NULL)
269 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
270 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
271 for (i=0; i < (ssize_t) number_threads; i++)
273 nexus_info[i]=(&nexus_info[0][i]);
274 nexus_info[i]->signature=MagickSignature;
280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284 + A c q u i r e P i x e l C a c h e P i x e l s %
288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290 % AcquirePixelCachePixels() returns the pixels associated with the specified
293 % The format of the AcquirePixelCachePixels() method is:
295 % const void *AcquirePixelCachePixels(const Image *image,
296 % MagickSizeType *length,ExceptionInfo *exception)
298 % A description of each parameter follows:
300 % o image: the image.
302 % o length: the pixel cache length.
304 % o exception: return any errors or warnings in this structure.
307 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
308 MagickSizeType *length,ExceptionInfo *exception)
313 assert(image != (const Image *) NULL);
314 assert(image->signature == MagickSignature);
315 assert(exception != (ExceptionInfo *) NULL);
316 assert(exception->signature == MagickSignature);
317 assert(image->cache != (Cache) NULL);
318 cache_info=(CacheInfo *) image->cache;
319 assert(cache_info->signature == MagickSignature);
321 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
322 return((const void *) NULL);
323 *length=cache_info->length;
324 return((const void *) cache_info->pixels);
328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332 + C a c h e C o m p o n e n t G e n e s i s %
336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338 % CacheComponentGenesis() instantiates the cache component.
340 % The format of the CacheComponentGenesis method is:
342 % MagickBooleanType CacheComponentGenesis(void)
345 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
347 AcquireSemaphoreInfo(&cache_semaphore);
352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356 + C a c h e C o m p o n e n t T e r m i n u s %
360 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 % CacheComponentTerminus() destroys the cache component.
364 % The format of the CacheComponentTerminus() method is:
366 % CacheComponentTerminus(void)
369 MagickPrivate void CacheComponentTerminus(void)
371 if (cache_semaphore == (SemaphoreInfo *) NULL)
372 AcquireSemaphoreInfo(&cache_semaphore);
373 LockSemaphoreInfo(cache_semaphore);
374 instantiate_cache=MagickFalse;
375 UnlockSemaphoreInfo(cache_semaphore);
376 DestroySemaphoreInfo(&cache_semaphore);
380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384 + C l o n e P i x e l C a c h e %
388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390 % ClonePixelCache() clones a pixel cache.
392 % The format of the ClonePixelCache() method is:
394 % Cache ClonePixelCache(const Cache cache)
396 % A description of each parameter follows:
398 % o cache: the pixel cache.
401 MagickPrivate Cache ClonePixelCache(const Cache cache)
409 assert(cache != NULL);
410 cache_info=(const CacheInfo *) cache;
411 assert(cache_info->signature == MagickSignature);
412 if (cache_info->debug != MagickFalse)
413 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
414 cache_info->filename);
415 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
416 if (clone_info == (Cache) NULL)
417 return((Cache) NULL);
418 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
419 return((Cache ) clone_info);
423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427 + C l o n e P i x e l C a c h e P i x e l s %
431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
432 % ClonePixelCachePixels() clones the source pixel cache to the destination
435 % The format of the ClonePixelCachePixels() method is:
437 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
438 % CacheInfo *source_info,ExceptionInfo *exception)
440 % A description of each parameter follows:
442 % o cache_info: the pixel cache.
444 % o source_info: the source pixel cache.
446 % o exception: return any errors or warnings in this structure.
450 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
456 if (cache_info->file != -1)
458 status=close(cache_info->file);
459 cache_info->file=(-1);
460 RelinquishMagickResource(FileResource,1);
462 return(status == -1 ? MagickFalse : MagickTrue);
465 static inline MagickSizeType MagickMax(const MagickSizeType x,
466 const MagickSizeType y)
473 static inline MagickSizeType MagickMin(const MagickSizeType x,
474 const MagickSizeType y)
481 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
488 Open pixel cache on disk.
490 if (cache_info->file != -1)
491 return(MagickTrue); /* cache already open */
492 if (*cache_info->cache_filename == '\0')
493 file=AcquireUniqueFileResource(cache_info->cache_filename);
499 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
504 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
505 O_BINARY | O_EXCL,S_MODE);
507 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
513 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
516 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
522 (void) AcquireMagickResource(FileResource,1);
523 cache_info->file=file;
524 cache_info->mode=mode;
528 static inline MagickOffsetType ReadPixelCacheRegion(
529 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
530 const MagickSizeType length,unsigned char *restrict buffer)
532 register MagickOffsetType
538 #if !defined(MAGICKCORE_HAVE_PREAD)
539 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
540 return((MagickOffsetType) -1);
543 for (i=0; i < (MagickOffsetType) length; i+=count)
545 #if !defined(MAGICKCORE_HAVE_PREAD)
546 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
547 (MagickSizeType) SSIZE_MAX));
549 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
550 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
562 static inline MagickOffsetType WritePixelCacheRegion(
563 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
564 const MagickSizeType length,const unsigned char *restrict buffer)
566 register MagickOffsetType
572 #if !defined(MAGICKCORE_HAVE_PWRITE)
573 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
574 return((MagickOffsetType) -1);
577 for (i=0; i < (MagickOffsetType) length; i+=count)
579 #if !defined(MAGICKCORE_HAVE_PWRITE)
580 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
581 (MagickSizeType) SSIZE_MAX));
583 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
584 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
596 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
597 CacheInfo *cache_info,ExceptionInfo *exception)
602 register MagickOffsetType
612 Clone pixel cache (both caches on disk).
614 if (cache_info->debug != MagickFalse)
615 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
616 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
618 if (blob == (unsigned char *) NULL)
620 (void) ThrowMagickException(exception,GetMagickModule(),
621 ResourceLimitError,"MemoryAllocationFailed","`%s'",
622 cache_info->filename);
625 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
627 blob=(unsigned char *) RelinquishMagickMemory(blob);
628 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
629 cache_info->cache_filename);
632 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
634 (void) ClosePixelCacheOnDisk(cache_info);
635 blob=(unsigned char *) RelinquishMagickMemory(blob);
636 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
637 clone_info->cache_filename);
641 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
643 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
644 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
648 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
649 cache_info->cache_filename);
652 length=(size_t) count;
653 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
654 if ((MagickSizeType) count != length)
656 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
657 clone_info->cache_filename);
661 (void) ClosePixelCacheOnDisk(clone_info);
662 (void) ClosePixelCacheOnDisk(cache_info);
663 blob=(unsigned char *) RelinquishMagickMemory(blob);
664 if (i < (MagickOffsetType) cache_info->length)
669 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
670 CacheInfo *cache_info,ExceptionInfo *exception)
675 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
678 Clone pixel cache (both caches in memory).
680 if (cache_info->debug != MagickFalse)
681 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
682 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
686 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
689 Clone pixel cache (one cache on disk, one in memory).
691 if (cache_info->debug != MagickFalse)
692 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
693 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
695 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
696 cache_info->cache_filename);
699 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
700 cache_info->length,(unsigned char *) clone_info->pixels);
701 (void) ClosePixelCacheOnDisk(cache_info);
702 if ((MagickSizeType) count != cache_info->length)
704 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
705 cache_info->cache_filename);
710 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
713 Clone pixel cache (one cache on disk, one in memory).
715 if (clone_info->debug != MagickFalse)
716 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
717 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
719 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
720 clone_info->cache_filename);
723 count=WritePixelCacheRegion(clone_info,clone_info->offset,
724 clone_info->length,(unsigned char *) cache_info->pixels);
725 (void) ClosePixelCacheOnDisk(clone_info);
726 if ((MagickSizeType) count != clone_info->length)
728 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
729 clone_info->cache_filename);
735 Clone pixel cache (both caches on disk).
737 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
740 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
741 CacheInfo *cache_info,ExceptionInfo *exception)
754 register unsigned char
767 Clone pixel cache (unoptimized).
769 if (cache_info->debug != MagickFalse)
771 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
772 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
774 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
775 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
777 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
778 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
780 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
782 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
783 clone_info->number_channels)*sizeof(Quantum),MagickMax(
784 cache_info->metacontent_extent,clone_info->metacontent_extent));
785 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
786 if (blob == (unsigned char *) NULL)
788 (void) ThrowMagickException(exception,GetMagickModule(),
789 ResourceLimitError,"MemoryAllocationFailed","`%s'",
790 cache_info->filename);
793 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
796 if (cache_info->type == DiskCache)
798 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
800 blob=(unsigned char *) RelinquishMagickMemory(blob);
801 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
802 cache_info->cache_filename);
805 cache_offset=cache_info->offset;
807 if (clone_info->type == DiskCache)
809 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
811 blob=(unsigned char *) RelinquishMagickMemory(blob);
812 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
813 clone_info->cache_filename);
816 clone_offset=clone_info->offset;
819 Clone pixel channels.
823 for (y=0; y < (ssize_t) cache_info->rows; y++)
825 for (x=0; x < (ssize_t) cache_info->columns; x++)
831 Read a set of pixel channels.
833 length=cache_info->number_channels*sizeof(Quantum);
834 if (cache_info->type != DiskCache)
835 p=(unsigned char *) cache_info->pixels+cache_offset;
838 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
839 if ((MagickSizeType) count != length)
845 cache_offset+=length;
846 if ((y < (ssize_t) clone_info->rows) &&
847 (x < (ssize_t) clone_info->columns))
848 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
860 Write a set of pixel channels.
862 channel=clone_info->channel_map[i].channel;
863 traits=cache_info->channel_map[channel].traits;
864 if (traits == UndefinedPixelTrait)
866 clone_offset+=sizeof(Quantum);
869 offset=cache_info->channel_map[channel].offset;
870 if (clone_info->type != DiskCache)
871 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
872 offset*sizeof(Quantum),sizeof(Quantum));
875 count=WritePixelCacheRegion(clone_info,clone_offset,
876 sizeof(Quantum),p+offset*sizeof(Quantum));
877 if ((MagickSizeType) count != sizeof(Quantum))
883 clone_offset+=sizeof(Quantum);
886 if (y < (ssize_t) clone_info->rows)
889 Set remaining columns as undefined.
891 length=clone_info->number_channels*sizeof(Quantum);
892 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
893 for ( ; x < (ssize_t) clone_info->columns; x++)
895 if (clone_info->type != DiskCache)
896 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
900 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
901 if ((MagickSizeType) count != length)
907 clone_offset+=length;
911 length=clone_info->number_channels*sizeof(Quantum);
912 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
913 for ( ; y < (ssize_t) clone_info->rows; y++)
916 Set remaining rows as undefined.
918 for (x=0; x < (ssize_t) clone_info->columns; x++)
920 if (clone_info->type != DiskCache)
921 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
925 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
926 if ((MagickSizeType) count != length)
932 clone_offset+=length;
935 if ((cache_info->metacontent_extent != 0) ||
936 (clone_info->metacontent_extent != 0))
941 for (y=0; y < (ssize_t) cache_info->rows; y++)
943 for (x=0; x < (ssize_t) cache_info->columns; x++)
946 Read a set of metacontent.
948 length=cache_info->metacontent_extent;
949 if (cache_info->type != DiskCache)
950 p=(unsigned char *) cache_info->pixels+cache_offset;
953 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
954 if ((MagickSizeType) count != length)
960 cache_offset+=length;
961 if ((y < (ssize_t) clone_info->rows) &&
962 (x < (ssize_t) clone_info->columns))
965 Write a set of metacontent.
967 length=clone_info->metacontent_extent;
968 if (clone_info->type != DiskCache)
969 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
973 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
974 if ((MagickSizeType) count != length)
980 clone_offset+=length;
983 length=clone_info->metacontent_extent;
984 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
985 for ( ; x < (ssize_t) clone_info->columns; x++)
988 Set remaining columns as undefined.
990 if (clone_info->type != DiskCache)
991 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
995 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
996 if ((MagickSizeType) count != length)
1002 clone_offset+=length;
1005 if (y < (ssize_t) clone_info->rows)
1008 Set remaining rows as undefined.
1010 length=clone_info->metacontent_extent;
1011 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1012 for ( ; y < (ssize_t) clone_info->rows; y++)
1014 for (x=0; x < (ssize_t) clone_info->columns; x++)
1016 if (clone_info->type != DiskCache)
1017 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1021 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1023 if ((MagickSizeType) count != length)
1029 clone_offset+=length;
1034 if (clone_info->type == DiskCache)
1035 (void) ClosePixelCacheOnDisk(clone_info);
1036 if (cache_info->type == DiskCache)
1037 (void) ClosePixelCacheOnDisk(cache_info);
1038 blob=(unsigned char *) RelinquishMagickMemory(blob);
1042 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1043 CacheInfo *cache_info,ExceptionInfo *exception)
1049 if (cache_info->type == PingCache)
1051 p=cache_info->channel_map;
1052 q=clone_info->channel_map;
1053 if ((cache_info->columns == clone_info->columns) &&
1054 (cache_info->rows == clone_info->rows) &&
1055 (cache_info->number_channels == clone_info->number_channels) &&
1056 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1057 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1058 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1059 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1067 + C l o n e P i x e l C a c h e M e t h o d s %
1071 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1076 % The format of the ClonePixelCacheMethods() method is:
1078 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1080 % A description of each parameter follows:
1082 % o clone: Specifies a pointer to a Cache structure.
1084 % o cache: the pixel cache.
1087 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1093 assert(clone != (Cache) NULL);
1094 source_info=(CacheInfo *) clone;
1095 assert(source_info->signature == MagickSignature);
1096 if (source_info->debug != MagickFalse)
1097 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1098 source_info->filename);
1099 assert(cache != (Cache) NULL);
1100 cache_info=(CacheInfo *) cache;
1101 assert(cache_info->signature == MagickSignature);
1102 source_info->methods=cache_info->methods;
1106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1110 + D e s t r o y I m a g e P i x e l C a c h e %
1114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1116 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1118 % The format of the DestroyImagePixelCache() method is:
1120 % void DestroyImagePixelCache(Image *image)
1122 % A description of each parameter follows:
1124 % o image: the image.
1127 static void DestroyImagePixelCache(Image *image)
1129 assert(image != (Image *) NULL);
1130 assert(image->signature == MagickSignature);
1131 if (image->debug != MagickFalse)
1132 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1133 if (image->cache == (void *) NULL)
1135 image->cache=DestroyPixelCache(image->cache);
1139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1143 + D e s t r o y I m a g e P i x e l s %
1147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1149 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1151 % The format of the DestroyImagePixels() method is:
1153 % void DestroyImagePixels(Image *image)
1155 % A description of each parameter follows:
1157 % o image: the image.
1160 MagickExport void DestroyImagePixels(Image *image)
1165 assert(image != (const Image *) NULL);
1166 assert(image->signature == MagickSignature);
1167 if (image->debug != MagickFalse)
1168 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1169 assert(image->cache != (Cache) NULL);
1170 cache_info=(CacheInfo *) image->cache;
1171 assert(cache_info->signature == MagickSignature);
1172 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1174 cache_info->methods.destroy_pixel_handler(image);
1177 image->cache=DestroyPixelCache(image->cache);
1181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1185 + D e s t r o y P i x e l C a c h e %
1189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1191 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1193 % The format of the DestroyPixelCache() method is:
1195 % Cache DestroyPixelCache(Cache cache)
1197 % A description of each parameter follows:
1199 % o cache: the pixel cache.
1203 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1205 switch (cache_info->type)
1209 if (cache_info->mapped == MagickFalse)
1210 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
1211 cache_info->pixels);
1213 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1214 (size_t) cache_info->length);
1215 RelinquishMagickResource(MemoryResource,cache_info->length);
1220 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1221 cache_info->length);
1222 if (cache_info->mode != ReadMode)
1223 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1224 *cache_info->cache_filename='\0';
1225 RelinquishMagickResource(MapResource,cache_info->length);
1229 if (cache_info->file != -1)
1230 (void) ClosePixelCacheOnDisk(cache_info);
1231 if (cache_info->mode != ReadMode)
1232 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1233 *cache_info->cache_filename='\0';
1234 RelinquishMagickResource(DiskResource,cache_info->length);
1237 case DistributedCache:
1245 cache_info->type=UndefinedCache;
1246 cache_info->mapped=MagickFalse;
1247 cache_info->metacontent=(void *) NULL;
1250 MagickPrivate Cache DestroyPixelCache(Cache cache)
1255 assert(cache != (Cache) NULL);
1256 cache_info=(CacheInfo *) cache;
1257 assert(cache_info->signature == MagickSignature);
1258 if (cache_info->debug != MagickFalse)
1259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1260 cache_info->filename);
1261 LockSemaphoreInfo(cache_info->semaphore);
1262 cache_info->reference_count--;
1263 if (cache_info->reference_count != 0)
1265 UnlockSemaphoreInfo(cache_info->semaphore);
1266 return((Cache) NULL);
1268 UnlockSemaphoreInfo(cache_info->semaphore);
1269 if (cache_info->debug != MagickFalse)
1272 message[MaxTextExtent];
1274 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1275 cache_info->filename);
1276 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1278 RelinquishPixelCachePixels(cache_info);
1279 if (cache_info->distribute_cache_info != (DistributeCacheInfo *) NULL)
1280 cache_info->distribute_cache_info=
1281 DestroyDistributeCacheInfo(cache_info->distribute_cache_info);
1282 if (cache_info->nexus_info != (NexusInfo **) NULL)
1283 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1284 cache_info->number_threads);
1285 if (cache_info->random_info != (RandomInfo *) NULL)
1286 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1287 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
1288 DestroySemaphoreInfo(&cache_info->file_semaphore);
1289 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1290 DestroySemaphoreInfo(&cache_info->semaphore);
1291 cache_info->signature=(~MagickSignature);
1292 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302 + D e s t r o y P i x e l C a c h e N e x u s %
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1310 % The format of the DestroyPixelCacheNexus() method is:
1312 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1313 % const size_t number_threads)
1315 % A description of each parameter follows:
1317 % o nexus_info: the nexus to destroy.
1319 % o number_threads: the number of nexus threads.
1323 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1325 if (nexus_info->mapped == MagickFalse)
1326 (void) RelinquishAlignedMemory(nexus_info->cache);
1328 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1329 nexus_info->cache=(Quantum *) NULL;
1330 nexus_info->pixels=(Quantum *) NULL;
1331 nexus_info->metacontent=(void *) NULL;
1332 nexus_info->length=0;
1333 nexus_info->mapped=MagickFalse;
1336 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1337 const size_t number_threads)
1342 assert(nexus_info != (NexusInfo **) NULL);
1343 for (i=0; i < (ssize_t) number_threads; i++)
1345 if (nexus_info[i]->cache != (Quantum *) NULL)
1346 RelinquishCacheNexusPixels(nexus_info[i]);
1347 nexus_info[i]->signature=(~MagickSignature);
1349 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1350 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359 % G e t A u t h e n t i c M e t a c o n t e n t %
1363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1365 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1366 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1367 % returned if the associated pixels are not available.
1369 % The format of the GetAuthenticMetacontent() method is:
1371 % void *GetAuthenticMetacontent(const Image *image)
1373 % A description of each parameter follows:
1375 % o image: the image.
1378 MagickExport void *GetAuthenticMetacontent(const Image *image)
1384 id = GetOpenMPThreadId();
1389 assert(image != (const Image *) NULL);
1390 assert(image->signature == MagickSignature);
1391 assert(image->cache != (Cache) NULL);
1392 cache_info=(CacheInfo *) image->cache;
1393 assert(cache_info->signature == MagickSignature);
1394 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1395 (GetAuthenticMetacontentFromHandler) NULL)
1397 metacontent=cache_info->methods.
1398 get_authentic_metacontent_from_handler(image);
1399 return(metacontent);
1401 assert(id < (int) cache_info->number_threads);
1402 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1403 cache_info->nexus_info[id]);
1404 return(metacontent);
1408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1412 + 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 %
1416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1418 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1419 % with the last call to QueueAuthenticPixelsCache() or
1420 % GetAuthenticPixelsCache().
1422 % The format of the GetAuthenticMetacontentFromCache() method is:
1424 % void *GetAuthenticMetacontentFromCache(const Image *image)
1426 % A description of each parameter follows:
1428 % o image: the image.
1431 static void *GetAuthenticMetacontentFromCache(const Image *image)
1437 id = GetOpenMPThreadId();
1442 assert(image != (const Image *) NULL);
1443 assert(image->signature == MagickSignature);
1444 assert(image->cache != (Cache) NULL);
1445 cache_info=(CacheInfo *) image->cache;
1446 assert(cache_info->signature == MagickSignature);
1447 assert(id < (int) cache_info->number_threads);
1448 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1449 cache_info->nexus_info[id]);
1450 return(metacontent);
1454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1458 + 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 %
1462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1464 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1465 % disk pixel cache as defined by the geometry parameters. A pointer to the
1466 % pixels is returned if the pixels are transferred, otherwise a NULL is
1469 % The format of the GetAuthenticPixelCacheNexus() method is:
1471 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1472 % const ssize_t y,const size_t columns,const size_t rows,
1473 % NexusInfo *nexus_info,ExceptionInfo *exception)
1475 % A description of each parameter follows:
1477 % o image: the image.
1479 % o x,y,columns,rows: These values define the perimeter of a region of
1482 % o nexus_info: the cache nexus to return.
1484 % o exception: return any errors or warnings in this structure.
1488 static inline MagickBooleanType IsPixelAuthentic(
1489 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1497 if (cache_info->type == PingCache)
1499 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1500 nexus_info->region.x;
1501 status=nexus_info->pixels == (cache_info->pixels+offset*
1502 cache_info->number_channels) ? MagickTrue : MagickFalse;
1506 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1507 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1508 NexusInfo *nexus_info,ExceptionInfo *exception)
1517 Transfer pixels from the cache.
1519 assert(image != (Image *) NULL);
1520 assert(image->signature == MagickSignature);
1521 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1523 if (q == (Quantum *) NULL)
1524 return((Quantum *) NULL);
1525 cache_info=(CacheInfo *) image->cache;
1526 assert(cache_info->signature == MagickSignature);
1527 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1529 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1530 return((Quantum *) NULL);
1531 if (cache_info->metacontent_extent != 0)
1532 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1533 return((Quantum *) NULL);
1538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1542 + 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 %
1546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1548 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1549 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1551 % The format of the GetAuthenticPixelsFromCache() method is:
1553 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1555 % A description of each parameter follows:
1557 % o image: the image.
1560 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1566 id = GetOpenMPThreadId();
1568 assert(image != (const Image *) NULL);
1569 assert(image->signature == MagickSignature);
1570 assert(image->cache != (Cache) NULL);
1571 cache_info=(CacheInfo *) image->cache;
1572 assert(cache_info->signature == MagickSignature);
1573 assert(id < (int) cache_info->number_threads);
1574 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1582 % G e t A u t h e n t i c P i x e l Q u e u e %
1586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1588 % GetAuthenticPixelQueue() returns the authentic pixels associated
1589 % corresponding with the last call to QueueAuthenticPixels() or
1590 % GetAuthenticPixels().
1592 % The format of the GetAuthenticPixelQueue() method is:
1594 % Quantum *GetAuthenticPixelQueue(const Image image)
1596 % A description of each parameter follows:
1598 % o image: the image.
1601 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1607 id = GetOpenMPThreadId();
1609 assert(image != (const Image *) NULL);
1610 assert(image->signature == MagickSignature);
1611 assert(image->cache != (Cache) NULL);
1612 cache_info=(CacheInfo *) image->cache;
1613 assert(cache_info->signature == MagickSignature);
1614 if (cache_info->methods.get_authentic_pixels_from_handler !=
1615 (GetAuthenticPixelsFromHandler) NULL)
1616 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1617 assert(id < (int) cache_info->number_threads);
1618 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1626 % G e t A u t h e n t i c P i x e l s %
1629 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1632 % region is successfully accessed, a pointer to a Quantum array
1633 % representing the region is returned, otherwise NULL is returned.
1635 % The returned pointer may point to a temporary working copy of the pixels
1636 % or it may point to the original pixels in memory. Performance is maximized
1637 % if the selected region is part of one row, or one or more full rows, since
1638 % then there is opportunity to access the pixels in-place (without a copy)
1639 % if the image is in memory, or in a memory-mapped file. The returned pointer
1640 % must *never* be deallocated by the user.
1642 % Pixels accessed via the returned pointer represent a simple array of type
1643 % Quantum. If the image has corresponding metacontent,call
1644 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1645 % meta-content corresponding to the region. Once the Quantum array has
1646 % been updated, the changes must be saved back to the underlying image using
1647 % SyncAuthenticPixels() or they may be lost.
1649 % The format of the GetAuthenticPixels() method is:
1651 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1652 % const ssize_t y,const size_t columns,const size_t rows,
1653 % ExceptionInfo *exception)
1655 % A description of each parameter follows:
1657 % o image: the image.
1659 % o x,y,columns,rows: These values define the perimeter of a region of
1662 % o exception: return any errors or warnings in this structure.
1665 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1666 const ssize_t y,const size_t columns,const size_t rows,
1667 ExceptionInfo *exception)
1673 id = GetOpenMPThreadId();
1678 assert(image != (Image *) NULL);
1679 assert(image->signature == MagickSignature);
1680 assert(image->cache != (Cache) NULL);
1681 cache_info=(CacheInfo *) image->cache;
1682 assert(cache_info->signature == MagickSignature);
1683 if (cache_info->methods.get_authentic_pixels_handler !=
1684 (GetAuthenticPixelsHandler) NULL)
1686 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1690 assert(id < (int) cache_info->number_threads);
1691 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1692 cache_info->nexus_info[id],exception);
1697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1701 + G e t A u t h e n t i c P i x e l s C a c h e %
1705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1707 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1708 % as defined by the geometry parameters. A pointer to the pixels is returned
1709 % if the pixels are transferred, otherwise a NULL is returned.
1711 % The format of the GetAuthenticPixelsCache() method is:
1713 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1714 % const ssize_t y,const size_t columns,const size_t rows,
1715 % ExceptionInfo *exception)
1717 % A description of each parameter follows:
1719 % o image: the image.
1721 % o x,y,columns,rows: These values define the perimeter of a region of
1724 % o exception: return any errors or warnings in this structure.
1727 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1728 const ssize_t y,const size_t columns,const size_t rows,
1729 ExceptionInfo *exception)
1735 id = GetOpenMPThreadId();
1740 assert(image != (const Image *) NULL);
1741 assert(image->signature == MagickSignature);
1742 assert(image->cache != (Cache) NULL);
1743 cache_info=(CacheInfo *) image->cache;
1744 if (cache_info == (Cache) NULL)
1745 return((Quantum *) NULL);
1746 assert(cache_info->signature == MagickSignature);
1747 assert(id < (int) cache_info->number_threads);
1748 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1749 cache_info->nexus_info[id],exception);
1754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1758 + G e t I m a g e E x t e n t %
1762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1764 % GetImageExtent() returns the extent of the pixels associated corresponding
1765 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1767 % The format of the GetImageExtent() method is:
1769 % MagickSizeType GetImageExtent(const Image *image)
1771 % A description of each parameter follows:
1773 % o image: the image.
1776 MagickExport MagickSizeType GetImageExtent(const Image *image)
1782 id = GetOpenMPThreadId();
1784 assert(image != (Image *) NULL);
1785 assert(image->signature == MagickSignature);
1786 if (image->debug != MagickFalse)
1787 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1788 assert(image->cache != (Cache) NULL);
1789 cache_info=(CacheInfo *) image->cache;
1790 assert(cache_info->signature == MagickSignature);
1791 assert(id < (int) cache_info->number_threads);
1792 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1800 + G e t I m a g e P i x e l C a c h e %
1804 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1806 % GetImagePixelCache() ensures that there is only a single reference to the
1807 % pixel cache to be modified, updating the provided cache pointer to point to
1808 % a clone of the original pixel cache if necessary.
1810 % The format of the GetImagePixelCache method is:
1812 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1813 % ExceptionInfo *exception)
1815 % A description of each parameter follows:
1817 % o image: the image.
1819 % o clone: any value other than MagickFalse clones the cache pixels.
1821 % o exception: return any errors or warnings in this structure.
1825 static inline MagickBooleanType ValidatePixelCacheMorphology(
1826 const Image *restrict image)
1829 *restrict cache_info;
1831 const PixelChannelMap
1836 Does the image match the pixel cache morphology?
1838 cache_info=(CacheInfo *) image->cache;
1839 p=image->channel_map;
1840 q=cache_info->channel_map;
1841 if ((image->storage_class != cache_info->storage_class) ||
1842 (image->colorspace != cache_info->colorspace) ||
1843 (image->alpha_trait != cache_info->alpha_trait) ||
1844 (image->mask != cache_info->mask) ||
1845 (image->columns != cache_info->columns) ||
1846 (image->rows != cache_info->rows) ||
1847 (image->number_channels != cache_info->number_channels) ||
1848 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1849 (image->metacontent_extent != cache_info->metacontent_extent) ||
1850 (cache_info->nexus_info == (NexusInfo **) NULL))
1851 return(MagickFalse);
1855 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1856 ExceptionInfo *exception)
1865 static MagickSizeType
1871 cache_timestamp = 0;
1874 LockSemaphoreInfo(image->semaphore);
1875 if (cpu_throttle == 0)
1881 Set CPU throttle in milleseconds.
1883 cpu_throttle=MagickResourceInfinity;
1884 limit=GetEnvironmentValue("MAGICK_THROTTLE");
1885 if (limit == (char *) NULL)
1886 limit=GetPolicyValue("throttle");
1887 if (limit != (char *) NULL)
1889 cpu_throttle=(MagickSizeType) StringToInteger(limit);
1890 limit=DestroyString(limit);
1893 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
1894 MagickDelay(cpu_throttle);
1895 if (time_limit == 0)
1898 Set the expire time in seconds.
1900 time_limit=GetMagickResourceLimit(TimeResource);
1901 cache_timestamp=time((time_t *) NULL);
1903 if ((time_limit != MagickResourceInfinity) &&
1904 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
1905 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
1906 assert(image->cache != (Cache) NULL);
1907 cache_info=(CacheInfo *) image->cache;
1908 destroy=MagickFalse;
1909 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1911 LockSemaphoreInfo(cache_info->semaphore);
1912 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1923 clone_image=(*image);
1924 clone_image.semaphore=AllocateSemaphoreInfo();
1925 clone_image.reference_count=1;
1926 clone_image.cache=ClonePixelCache(cache_info);
1927 clone_info=(CacheInfo *) clone_image.cache;
1928 status=OpenPixelCache(&clone_image,IOMode,exception);
1929 if (status != MagickFalse)
1931 if (clone != MagickFalse)
1932 status=ClonePixelCachePixels(clone_info,cache_info,exception);
1933 if (status != MagickFalse)
1935 if (cache_info->reference_count == 1)
1936 cache_info->nexus_info=(NexusInfo **) NULL;
1938 image->cache=clone_image.cache;
1941 DestroySemaphoreInfo(&clone_image.semaphore);
1943 UnlockSemaphoreInfo(cache_info->semaphore);
1945 if (destroy != MagickFalse)
1946 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
1947 if (status != MagickFalse)
1950 Ensure the image matches the pixel cache morphology.
1952 image->taint=MagickTrue;
1953 image->type=UndefinedType;
1954 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1956 status=OpenPixelCache(image,IOMode,exception);
1957 cache_info=(CacheInfo *) image->cache;
1958 if (cache_info->type == DiskCache)
1959 (void) ClosePixelCacheOnDisk(cache_info);
1962 UnlockSemaphoreInfo(image->semaphore);
1963 if (status == MagickFalse)
1964 return((Cache) NULL);
1965 return(image->cache);
1969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1973 + G e t I m a g e P i x e l C a c h e T y p e %
1977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1979 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
1980 % DiskCache, MemoryCache, MapCache, or PingCache.
1982 % The format of the GetImagePixelCacheType() method is:
1984 % CacheType GetImagePixelCacheType(const Image *image)
1986 % A description of each parameter follows:
1988 % o image: the image.
1991 MagickExport CacheType GetImagePixelCacheType(const Image *image)
1996 assert(image != (Image *) NULL);
1997 assert(image->signature == MagickSignature);
1998 assert(image->cache != (Cache) NULL);
1999 cache_info=(CacheInfo *) image->cache;
2000 assert(cache_info->signature == MagickSignature);
2001 return(cache_info->type);
2005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2009 % G e t O n e A u t h e n t i c P i x e l %
2013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2015 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2016 % location. The image background color is returned if an error occurs.
2018 % The format of the GetOneAuthenticPixel() method is:
2020 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2021 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2023 % A description of each parameter follows:
2025 % o image: the image.
2027 % o x,y: These values define the location of the pixel to return.
2029 % o pixel: return a pixel at the specified (x,y) location.
2031 % o exception: return any errors or warnings in this structure.
2034 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2035 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2046 assert(image != (Image *) NULL);
2047 assert(image->signature == MagickSignature);
2048 assert(image->cache != (Cache) NULL);
2049 cache_info=(CacheInfo *) image->cache;
2050 assert(cache_info->signature == MagickSignature);
2051 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2052 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2053 (GetOneAuthenticPixelFromHandler) NULL)
2054 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2056 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2057 if (q == (Quantum *) NULL)
2059 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2060 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2061 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2062 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2063 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2064 return(MagickFalse);
2066 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2071 channel=GetPixelChannelChannel(image,i);
2072 pixel[channel]=q[i];
2078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2082 + 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 %
2086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2088 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2089 % location. The image background color is returned if an error occurs.
2091 % The format of the GetOneAuthenticPixelFromCache() method is:
2093 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2094 % const ssize_t x,const ssize_t y,Quantum *pixel,
2095 % ExceptionInfo *exception)
2097 % A description of each parameter follows:
2099 % o image: the image.
2101 % o x,y: These values define the location of the pixel to return.
2103 % o pixel: return a pixel at the specified (x,y) location.
2105 % o exception: return any errors or warnings in this structure.
2108 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2109 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2115 id = GetOpenMPThreadId();
2123 assert(image != (const Image *) NULL);
2124 assert(image->signature == MagickSignature);
2125 assert(image->cache != (Cache) NULL);
2126 cache_info=(CacheInfo *) image->cache;
2127 assert(cache_info->signature == MagickSignature);
2128 assert(id < (int) cache_info->number_threads);
2129 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2130 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2132 if (q == (Quantum *) NULL)
2134 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2135 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2136 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2137 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2138 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2139 return(MagickFalse);
2141 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2146 channel=GetPixelChannelChannel(image,i);
2147 pixel[channel]=q[i];
2153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2157 % G e t O n e V i r t u a l P i x e l %
2161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2163 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2164 % (x,y) location. The image background color is returned if an error occurs.
2165 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2167 % The format of the GetOneVirtualPixel() method is:
2169 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2170 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2172 % A description of each parameter follows:
2174 % o image: the image.
2176 % o x,y: These values define the location of the pixel to return.
2178 % o pixel: return a pixel at the specified (x,y) location.
2180 % o exception: return any errors or warnings in this structure.
2183 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2184 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2190 id = GetOpenMPThreadId();
2198 assert(image != (const Image *) NULL);
2199 assert(image->signature == MagickSignature);
2200 assert(image->cache != (Cache) NULL);
2201 cache_info=(CacheInfo *) image->cache;
2202 assert(cache_info->signature == MagickSignature);
2203 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2204 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2205 (GetOneVirtualPixelFromHandler) NULL)
2206 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2207 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2208 assert(id < (int) cache_info->number_threads);
2209 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2210 1UL,1UL,cache_info->nexus_info[id],exception);
2211 if (p == (const Quantum *) NULL)
2213 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2214 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2215 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2216 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2217 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2218 return(MagickFalse);
2220 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2225 channel=GetPixelChannelChannel(image,i);
2226 pixel[channel]=p[i];
2232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2236 + 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 %
2240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2242 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2243 % specified (x,y) location. The image background color is returned if an
2246 % The format of the GetOneVirtualPixelFromCache() method is:
2248 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2249 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2250 % Quantum *pixel,ExceptionInfo *exception)
2252 % A description of each parameter follows:
2254 % o image: the image.
2256 % o virtual_pixel_method: the virtual pixel method.
2258 % o x,y: These values define the location of the pixel to return.
2260 % o pixel: return a pixel at the specified (x,y) location.
2262 % o exception: return any errors or warnings in this structure.
2265 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2266 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2267 Quantum *pixel,ExceptionInfo *exception)
2273 id = GetOpenMPThreadId();
2281 assert(image != (const Image *) NULL);
2282 assert(image->signature == MagickSignature);
2283 assert(image->cache != (Cache) NULL);
2284 cache_info=(CacheInfo *) image->cache;
2285 assert(cache_info->signature == MagickSignature);
2286 assert(id < (int) cache_info->number_threads);
2287 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2288 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2289 cache_info->nexus_info[id],exception);
2290 if (p == (const Quantum *) NULL)
2292 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2293 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2294 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2295 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2296 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2297 return(MagickFalse);
2299 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2304 channel=GetPixelChannelChannel(image,i);
2305 pixel[channel]=p[i];
2311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2315 % G e t O n e V i r t u a l P i x e l I n f o %
2319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2321 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2322 % location. The image background color is returned if an error occurs. If
2323 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2325 % The format of the GetOneVirtualPixelInfo() method is:
2327 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2328 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2329 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2331 % A description of each parameter follows:
2333 % o image: the image.
2335 % o virtual_pixel_method: the virtual pixel method.
2337 % o x,y: these values define the location of the pixel to return.
2339 % o pixel: return a pixel at the specified (x,y) location.
2341 % o exception: return any errors or warnings in this structure.
2344 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2345 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2346 PixelInfo *pixel,ExceptionInfo *exception)
2352 id = GetOpenMPThreadId();
2354 register const Quantum
2357 assert(image != (const Image *) NULL);
2358 assert(image->signature == MagickSignature);
2359 assert(image->cache != (Cache) NULL);
2360 cache_info=(CacheInfo *) image->cache;
2361 assert(cache_info->signature == MagickSignature);
2362 assert(id < (int) cache_info->number_threads);
2363 GetPixelInfo(image,pixel);
2364 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2365 cache_info->nexus_info[id],exception);
2366 if (p == (const Quantum *) NULL)
2367 return(MagickFalse);
2368 GetPixelInfoPixel(image,p,pixel);
2373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2377 + G e t P i x e l C a c h e C o l o r s p a c e %
2381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2383 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2385 % The format of the GetPixelCacheColorspace() method is:
2387 % Colorspace GetPixelCacheColorspace(Cache cache)
2389 % A description of each parameter follows:
2391 % o cache: the pixel cache.
2394 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2399 assert(cache != (Cache) NULL);
2400 cache_info=(CacheInfo *) cache;
2401 assert(cache_info->signature == MagickSignature);
2402 if (cache_info->debug != MagickFalse)
2403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2404 cache_info->filename);
2405 return(cache_info->colorspace);
2409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2413 + G e t P i x e l C a c h e M e t h o d s %
2417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2419 % GetPixelCacheMethods() initializes the CacheMethods structure.
2421 % The format of the GetPixelCacheMethods() method is:
2423 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2425 % A description of each parameter follows:
2427 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2430 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2432 assert(cache_methods != (CacheMethods *) NULL);
2433 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2434 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2435 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2436 cache_methods->get_virtual_metacontent_from_handler=
2437 GetVirtualMetacontentFromCache;
2438 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2439 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2440 cache_methods->get_authentic_metacontent_from_handler=
2441 GetAuthenticMetacontentFromCache;
2442 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2443 cache_methods->get_one_authentic_pixel_from_handler=
2444 GetOneAuthenticPixelFromCache;
2445 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2446 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2447 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2455 + G e t P i x e l C a c h e N e x u s E x t e n t %
2459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2461 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2462 % corresponding with the last call to SetPixelCacheNexusPixels() or
2463 % GetPixelCacheNexusPixels().
2465 % The format of the GetPixelCacheNexusExtent() method is:
2467 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2468 % NexusInfo *nexus_info)
2470 % A description of each parameter follows:
2472 % o nexus_info: the nexus info.
2475 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2476 NexusInfo *nexus_info)
2484 assert(cache != NULL);
2485 cache_info=(CacheInfo *) cache;
2486 assert(cache_info->signature == MagickSignature);
2487 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2489 return((MagickSizeType) cache_info->columns*cache_info->rows);
2494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2498 + 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 %
2502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2504 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2507 % The format of the GetPixelCacheNexusMetacontent() method is:
2509 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2510 % NexusInfo *nexus_info)
2512 % A description of each parameter follows:
2514 % o cache: the pixel cache.
2516 % o nexus_info: the cache nexus to return the meta-content.
2519 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2520 NexusInfo *nexus_info)
2525 assert(cache != NULL);
2526 cache_info=(CacheInfo *) cache;
2527 assert(cache_info->signature == MagickSignature);
2528 if (cache_info->storage_class == UndefinedClass)
2529 return((void *) NULL);
2530 return(nexus_info->metacontent);
2534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2538 + G e t P i x e l C a c h e N e x u s P i x e l s %
2542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2544 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2547 % The format of the GetPixelCacheNexusPixels() method is:
2549 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2550 % NexusInfo *nexus_info)
2552 % A description of each parameter follows:
2554 % o cache: the pixel cache.
2556 % o nexus_info: the cache nexus to return the pixels.
2559 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2560 NexusInfo *nexus_info)
2565 assert(cache != NULL);
2566 cache_info=(CacheInfo *) cache;
2567 assert(cache_info->signature == MagickSignature);
2568 if (cache_info->storage_class == UndefinedClass)
2569 return((Quantum *) NULL);
2570 return(nexus_info->pixels);
2574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2578 + G e t P i x e l C a c h e P i x e l s %
2582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2584 % GetPixelCachePixels() returns the pixels associated with the specified image.
2586 % The format of the GetPixelCachePixels() method is:
2588 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2589 % ExceptionInfo *exception)
2591 % A description of each parameter follows:
2593 % o image: the image.
2595 % o length: the pixel cache length.
2597 % o exception: return any errors or warnings in this structure.
2600 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2601 ExceptionInfo *exception)
2606 assert(image != (const Image *) NULL);
2607 assert(image->signature == MagickSignature);
2608 assert(image->cache != (Cache) NULL);
2609 assert(length != (MagickSizeType *) NULL);
2610 assert(exception != (ExceptionInfo *) NULL);
2611 assert(exception->signature == MagickSignature);
2612 cache_info=(CacheInfo *) image->cache;
2613 assert(cache_info->signature == MagickSignature);
2615 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2616 return((void *) NULL);
2617 *length=cache_info->length;
2618 return((void *) cache_info->pixels);
2622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2626 + 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 %
2630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2632 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2634 % The format of the GetPixelCacheStorageClass() method is:
2636 % ClassType GetPixelCacheStorageClass(Cache cache)
2638 % A description of each parameter follows:
2640 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2642 % o cache: the pixel cache.
2645 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2650 assert(cache != (Cache) NULL);
2651 cache_info=(CacheInfo *) cache;
2652 assert(cache_info->signature == MagickSignature);
2653 if (cache_info->debug != MagickFalse)
2654 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2655 cache_info->filename);
2656 return(cache_info->storage_class);
2660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2664 + G e t P i x e l C a c h e T i l e S i z e %
2668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2670 % GetPixelCacheTileSize() returns the pixel cache tile size.
2672 % The format of the GetPixelCacheTileSize() method is:
2674 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2677 % A description of each parameter follows:
2679 % o image: the image.
2681 % o width: the optimize cache tile width in pixels.
2683 % o height: the optimize cache tile height in pixels.
2686 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2692 assert(image != (Image *) NULL);
2693 assert(image->signature == MagickSignature);
2694 if (image->debug != MagickFalse)
2695 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2696 cache_info=(CacheInfo *) image->cache;
2697 assert(cache_info->signature == MagickSignature);
2698 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2699 if (GetImagePixelCacheType(image) == DiskCache)
2700 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2709 + 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 %
2713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2715 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2716 % pixel cache. A virtual pixel is any pixel access that is outside the
2717 % boundaries of the image cache.
2719 % The format of the GetPixelCacheVirtualMethod() method is:
2721 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2723 % A description of each parameter follows:
2725 % o image: the image.
2728 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2733 assert(image != (Image *) NULL);
2734 assert(image->signature == MagickSignature);
2735 assert(image->cache != (Cache) NULL);
2736 cache_info=(CacheInfo *) image->cache;
2737 assert(cache_info->signature == MagickSignature);
2738 return(cache_info->virtual_pixel_method);
2742 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2746 + 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 %
2750 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2752 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2753 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2755 % The format of the GetVirtualMetacontentFromCache() method is:
2757 % void *GetVirtualMetacontentFromCache(const Image *image)
2759 % A description of each parameter follows:
2761 % o image: the image.
2764 static const void *GetVirtualMetacontentFromCache(const Image *image)
2770 id = GetOpenMPThreadId();
2775 assert(image != (const Image *) NULL);
2776 assert(image->signature == MagickSignature);
2777 assert(image->cache != (Cache) NULL);
2778 cache_info=(CacheInfo *) image->cache;
2779 assert(cache_info->signature == MagickSignature);
2780 assert(id < (int) cache_info->number_threads);
2781 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2782 cache_info->nexus_info[id]);
2783 return(metacontent);
2787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2791 + 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 %
2795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2797 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2800 % The format of the GetVirtualMetacontentFromNexus() method is:
2802 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2803 % NexusInfo *nexus_info)
2805 % A description of each parameter follows:
2807 % o cache: the pixel cache.
2809 % o nexus_info: the cache nexus to return the meta-content.
2812 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2813 NexusInfo *nexus_info)
2818 assert(cache != (Cache) NULL);
2819 cache_info=(CacheInfo *) cache;
2820 assert(cache_info->signature == MagickSignature);
2821 if (cache_info->storage_class == UndefinedClass)
2822 return((void *) NULL);
2823 return(nexus_info->metacontent);
2827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2831 % G e t V i r t u a l M e t a c o n t e n t %
2835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2837 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2838 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2839 % returned if the meta-content are not available.
2841 % The format of the GetVirtualMetacontent() method is:
2843 % const void *GetVirtualMetacontent(const Image *image)
2845 % A description of each parameter follows:
2847 % o image: the image.
2850 MagickExport const void *GetVirtualMetacontent(const Image *image)
2856 id = GetOpenMPThreadId();
2861 assert(image != (const Image *) NULL);
2862 assert(image->signature == MagickSignature);
2863 assert(image->cache != (Cache) NULL);
2864 cache_info=(CacheInfo *) image->cache;
2865 assert(cache_info->signature == MagickSignature);
2866 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
2867 if (metacontent != (void *) NULL)
2868 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,ReadMode,®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 *) MagickAssumeAligned(AcquireAlignedMemory(1,
3671 (size_t) 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 SetPixelCacheExtent(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 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3707 return(MagickFalse);
3708 if ((MagickSizeType) offset >= length)
3710 extent=(MagickOffsetType) length-1;
3711 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3712 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3713 if (cache_info->synchronize != MagickFalse)
3718 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3720 return(MagickFalse);
3723 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3726 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3727 ExceptionInfo *exception)
3734 format[MaxTextExtent],
3735 message[MaxTextExtent];
3748 assert(image != (const Image *) NULL);
3749 assert(image->signature == MagickSignature);
3750 assert(image->cache != (Cache) NULL);
3751 if (image->debug != MagickFalse)
3752 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3753 if ((image->columns == 0) || (image->rows == 0))
3754 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3755 cache_info=(CacheInfo *) image->cache;
3756 assert(cache_info->signature == MagickSignature);
3757 source_info=(*cache_info);
3758 source_info.file=(-1);
3759 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3760 image->filename,(double) GetImageIndexInList(image));
3761 cache_info->storage_class=image->storage_class;
3762 cache_info->colorspace=image->colorspace;
3763 cache_info->alpha_trait=image->alpha_trait;
3764 cache_info->mask=image->mask;
3765 cache_info->rows=image->rows;
3766 cache_info->columns=image->columns;
3767 InitializePixelChannelMap(image);
3768 cache_info->number_channels=GetPixelChannels(image);
3769 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3770 sizeof(*image->channel_map));
3771 cache_info->metacontent_extent=image->metacontent_extent;
3772 cache_info->mode=mode;
3773 if (image->ping != MagickFalse)
3775 cache_info->type=PingCache;
3776 cache_info->pixels=(Quantum *) NULL;
3777 cache_info->metacontent=(void *) NULL;
3778 cache_info->length=0;
3781 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3782 packet_size=cache_info->number_channels*sizeof(Quantum);
3783 if (image->metacontent_extent != 0)
3784 packet_size+=cache_info->metacontent_extent;
3785 length=number_pixels*packet_size;
3786 columns=(size_t) (length/cache_info->rows/packet_size);
3787 if (cache_info->columns != columns)
3788 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3790 cache_info->length=length;
3791 status=AcquireMagickResource(AreaResource,cache_info->length);
3792 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3793 cache_info->metacontent_extent);
3794 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3796 status=AcquireMagickResource(MemoryResource,cache_info->length);
3797 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3798 (cache_info->type == MemoryCache))
3800 AllocatePixelCachePixels(cache_info);
3801 if (cache_info->pixels == (Quantum *) NULL)
3802 cache_info->pixels=source_info.pixels;
3806 Create memory pixel cache.
3809 cache_info->type=MemoryCache;
3810 cache_info->metacontent=(void *) NULL;
3811 if (cache_info->metacontent_extent != 0)
3812 cache_info->metacontent=(void *) (cache_info->pixels+
3813 number_pixels*cache_info->number_channels);
3814 if ((source_info.storage_class != UndefinedClass) &&
3817 status=ClonePixelCachePixels(cache_info,&source_info,
3819 RelinquishPixelCachePixels(&source_info);
3821 if (image->debug != MagickFalse)
3823 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3824 (void) FormatLocaleString(message,MaxTextExtent,
3825 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3826 cache_info->filename,cache_info->mapped != MagickFalse ?
3827 "anonymous" : "heap",(double) cache_info->columns,(double)
3828 cache_info->rows,(double) cache_info->number_channels,
3830 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3836 RelinquishMagickResource(MemoryResource,cache_info->length);
3839 Create pixel cache on disk.
3841 status=AcquireMagickResource(DiskResource,cache_info->length);
3842 if (status == MagickFalse)
3844 cache_info->distribute_cache_info=AcquireDistributeCacheInfo(exception);
3845 if (cache_info->distribute_cache_info != (DistributeCacheInfo *) NULL)
3847 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3848 "CacheResourcesExhausted","`%s'",image->filename);
3849 return(MagickFalse);
3851 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3853 (void) ClosePixelCacheOnDisk(cache_info);
3854 *cache_info->cache_filename='\0';
3856 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3858 RelinquishMagickResource(DiskResource,cache_info->length);
3859 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3861 return(MagickFalse);
3863 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
3864 cache_info->length);
3865 if (status == MagickFalse)
3867 ThrowFileException(exception,CacheError,"UnableToExtendCache",
3869 return(MagickFalse);
3871 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3872 cache_info->metacontent_extent);
3873 if (length != (MagickSizeType) ((size_t) length))
3874 cache_info->type=DiskCache;
3877 status=AcquireMagickResource(MapResource,cache_info->length);
3878 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
3879 (cache_info->type != MemoryCache))
3880 cache_info->type=DiskCache;
3883 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
3884 cache_info->offset,(size_t) cache_info->length);
3885 if (cache_info->pixels == (Quantum *) NULL)
3887 cache_info->type=DiskCache;
3888 cache_info->pixels=source_info.pixels;
3893 Create file-backed memory-mapped pixel cache.
3896 (void) ClosePixelCacheOnDisk(cache_info);
3897 cache_info->type=MapCache;
3898 cache_info->mapped=MagickTrue;
3899 cache_info->metacontent=(void *) NULL;
3900 if (cache_info->metacontent_extent != 0)
3901 cache_info->metacontent=(void *) (cache_info->pixels+
3902 number_pixels*cache_info->number_channels);
3903 if ((source_info.storage_class != UndefinedClass) &&
3906 status=ClonePixelCachePixels(cache_info,&source_info,
3908 RelinquishPixelCachePixels(&source_info);
3910 if (image->debug != MagickFalse)
3912 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3913 (void) FormatLocaleString(message,MaxTextExtent,
3914 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
3915 cache_info->filename,cache_info->cache_filename,
3916 cache_info->file,(double) cache_info->columns,(double)
3917 cache_info->rows,(double) cache_info->number_channels,
3919 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3925 RelinquishMagickResource(MapResource,cache_info->length);
3928 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3930 status=ClonePixelCachePixels(cache_info,&source_info,exception);
3931 RelinquishPixelCachePixels(&source_info);
3933 if (image->debug != MagickFalse)
3935 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
3936 (void) FormatLocaleString(message,MaxTextExtent,
3937 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
3938 cache_info->cache_filename,cache_info->file,(double)
3939 cache_info->columns,(double) cache_info->rows,(double)
3940 cache_info->number_channels,format);
3941 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3951 + P e r s i s t P i x e l C a c h e %
3955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3957 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
3958 % persistent pixel cache is one that resides on disk and is not destroyed
3959 % when the program exits.
3961 % The format of the PersistPixelCache() method is:
3963 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
3964 % const MagickBooleanType attach,MagickOffsetType *offset,
3965 % ExceptionInfo *exception)
3967 % A description of each parameter follows:
3969 % o image: the image.
3971 % o filename: the persistent pixel cache filename.
3973 % o attach: A value other than zero initializes the persistent pixel cache.
3975 % o initialize: A value other than zero initializes the persistent pixel
3978 % o offset: the offset in the persistent cache to store pixels.
3980 % o exception: return any errors or warnings in this structure.
3983 MagickExport MagickBooleanType PersistPixelCache(Image *image,
3984 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
3985 ExceptionInfo *exception)
4000 assert(image != (Image *) NULL);
4001 assert(image->signature == MagickSignature);
4002 if (image->debug != MagickFalse)
4003 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4004 assert(image->cache != (void *) NULL);
4005 assert(filename != (const char *) NULL);
4006 assert(offset != (MagickOffsetType *) NULL);
4007 page_size=GetMagickPageSize();
4008 cache_info=(CacheInfo *) image->cache;
4009 assert(cache_info->signature == MagickSignature);
4010 if (attach != MagickFalse)
4013 Attach existing persistent pixel cache.
4015 if (image->debug != MagickFalse)
4016 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4017 "attach persistent cache");
4018 (void) CopyMagickString(cache_info->cache_filename,filename,
4020 cache_info->type=DiskCache;
4021 cache_info->offset=(*offset);
4022 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4023 return(MagickFalse);
4024 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4027 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4028 (cache_info->reference_count == 1))
4030 LockSemaphoreInfo(cache_info->semaphore);
4031 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4032 (cache_info->reference_count == 1))
4038 Usurp existing persistent pixel cache.
4040 status=rename_utf8(cache_info->cache_filename,filename);
4043 (void) CopyMagickString(cache_info->cache_filename,filename,
4045 *offset+=cache_info->length+page_size-(cache_info->length %
4047 UnlockSemaphoreInfo(cache_info->semaphore);
4048 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4049 if (image->debug != MagickFalse)
4050 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4051 "Usurp resident persistent cache");
4055 UnlockSemaphoreInfo(cache_info->semaphore);
4058 Clone persistent pixel cache.
4060 clone_image=(*image);
4061 clone_info=(CacheInfo *) clone_image.cache;
4062 image->cache=ClonePixelCache(cache_info);
4063 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4064 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4065 cache_info->type=DiskCache;
4066 cache_info->offset=(*offset);
4067 cache_info=(CacheInfo *) image->cache;
4068 status=OpenPixelCache(image,IOMode,exception);
4069 if (status != MagickFalse)
4070 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4071 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4072 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4081 + 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 %
4085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4087 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4088 % defined by the region rectangle and returns a pointer to the region. This
4089 % region is subsequently transferred from the pixel cache with
4090 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4091 % pixels are transferred, otherwise a NULL is returned.
4093 % The format of the QueueAuthenticPixelCacheNexus() method is:
4095 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4096 % const ssize_t y,const size_t columns,const size_t rows,
4097 % const MagickBooleanType clone,NexusInfo *nexus_info,
4098 % ExceptionInfo *exception)
4100 % A description of each parameter follows:
4102 % o image: the image.
4104 % o x,y,columns,rows: These values define the perimeter of a region of
4107 % o nexus_info: the cache nexus to set.
4109 % o clone: clone the pixel cache.
4111 % o exception: return any errors or warnings in this structure.
4114 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4115 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4116 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4131 Validate pixel cache geometry.
4133 assert(image != (const Image *) NULL);
4134 assert(image->signature == MagickSignature);
4135 assert(image->cache != (Cache) NULL);
4136 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4137 if (cache_info == (Cache) NULL)
4138 return((Quantum *) NULL);
4139 assert(cache_info->signature == MagickSignature);
4140 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4142 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4143 "NoPixelsDefinedInCache","`%s'",image->filename);
4144 return((Quantum *) NULL);
4146 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4147 (y >= (ssize_t) cache_info->rows))
4149 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4150 "PixelsAreNotAuthentic","`%s'",image->filename);
4151 return((Quantum *) NULL);
4153 offset=(MagickOffsetType) y*cache_info->columns+x;
4155 return((Quantum *) NULL);
4156 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4157 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4158 if ((MagickSizeType) offset >= number_pixels)
4159 return((Quantum *) NULL);
4165 region.width=columns;
4167 return(SetPixelCacheNexusPixels(image,WriteMode,®ion,nexus_info,exception));
4171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4175 + 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 %
4179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4181 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4182 % defined by the region rectangle and returns a pointer to the region. This
4183 % region is subsequently transferred from the pixel cache with
4184 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4185 % pixels are transferred, otherwise a NULL is returned.
4187 % The format of the QueueAuthenticPixelsCache() method is:
4189 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4190 % const ssize_t y,const size_t columns,const size_t rows,
4191 % ExceptionInfo *exception)
4193 % A description of each parameter follows:
4195 % o image: the image.
4197 % o x,y,columns,rows: These values define the perimeter of a region of
4200 % o exception: return any errors or warnings in this structure.
4203 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4204 const ssize_t y,const size_t columns,const size_t rows,
4205 ExceptionInfo *exception)
4211 id = GetOpenMPThreadId();
4216 assert(image != (const Image *) NULL);
4217 assert(image->signature == MagickSignature);
4218 assert(image->cache != (Cache) NULL);
4219 cache_info=(CacheInfo *) image->cache;
4220 assert(cache_info->signature == MagickSignature);
4221 assert(id < (int) cache_info->number_threads);
4222 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4223 cache_info->nexus_info[id],exception);
4228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4232 % Q u e u e A u t h e n t i c P i x e l s %
4236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4238 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4239 % successfully initialized a pointer to a Quantum array representing the
4240 % region is returned, otherwise NULL is returned. The returned pointer may
4241 % point to a temporary working buffer for the pixels or it may point to the
4242 % final location of the pixels in memory.
4244 % Write-only access means that any existing pixel values corresponding to
4245 % the region are ignored. This is useful if the initial image is being
4246 % created from scratch, or if the existing pixel values are to be
4247 % completely replaced without need to refer to their pre-existing values.
4248 % The application is free to read and write the pixel buffer returned by
4249 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4250 % initialize the pixel array values. Initializing pixel array values is the
4251 % application's responsibility.
4253 % Performance is maximized if the selected region is part of one row, or
4254 % one or more full rows, since then there is opportunity to access the
4255 % pixels in-place (without a copy) if the image is in memory, or in a
4256 % memory-mapped file. The returned pointer must *never* be deallocated
4259 % Pixels accessed via the returned pointer represent a simple array of type
4260 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4261 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4262 % obtain the meta-content (of type void) corresponding to the region.
4263 % Once the Quantum (and/or Quantum) array has been updated, the
4264 % changes must be saved back to the underlying image using
4265 % SyncAuthenticPixels() or they may be lost.
4267 % The format of the QueueAuthenticPixels() method is:
4269 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4270 % const ssize_t y,const size_t columns,const size_t rows,
4271 % ExceptionInfo *exception)
4273 % A description of each parameter follows:
4275 % o image: the image.
4277 % o x,y,columns,rows: These values define the perimeter of a region of
4280 % o exception: return any errors or warnings in this structure.
4283 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4284 const ssize_t y,const size_t columns,const size_t rows,
4285 ExceptionInfo *exception)
4291 id = GetOpenMPThreadId();
4296 assert(image != (Image *) NULL);
4297 assert(image->signature == MagickSignature);
4298 assert(image->cache != (Cache) NULL);
4299 cache_info=(CacheInfo *) image->cache;
4300 assert(cache_info->signature == MagickSignature);
4301 if (cache_info->methods.queue_authentic_pixels_handler !=
4302 (QueueAuthenticPixelsHandler) NULL)
4304 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4308 assert(id < (int) cache_info->number_threads);
4309 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4310 cache_info->nexus_info[id],exception);
4315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4319 + 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 %
4323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4325 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4328 % The format of the ReadPixelCacheMetacontent() method is:
4330 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4331 % NexusInfo *nexus_info,ExceptionInfo *exception)
4333 % A description of each parameter follows:
4335 % o cache_info: the pixel cache.
4337 % o nexus_info: the cache nexus to read the metacontent.
4339 % o exception: return any errors or warnings in this structure.
4342 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4343 NexusInfo *nexus_info,ExceptionInfo *exception)
4356 register unsigned char
4362 if (cache_info->metacontent_extent == 0)
4363 return(MagickFalse);
4364 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4366 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4367 nexus_info->region.x;
4368 length=(MagickSizeType) nexus_info->region.width*
4369 cache_info->metacontent_extent;
4370 rows=nexus_info->region.height;
4372 q=(unsigned char *) nexus_info->metacontent;
4373 switch (cache_info->type)
4378 register unsigned char
4382 Read meta-content from memory.
4384 if ((cache_info->columns == nexus_info->region.width) &&
4385 (extent == (MagickSizeType) ((size_t) extent)))
4390 p=(unsigned char *) cache_info->metacontent+offset*
4391 cache_info->metacontent_extent;
4392 for (y=0; y < (ssize_t) rows; y++)
4394 (void) memcpy(q,p,(size_t) length);
4395 p+=cache_info->metacontent_extent*cache_info->columns;
4396 q+=cache_info->metacontent_extent*nexus_info->region.width;
4403 Read meta content from disk.
4405 LockSemaphoreInfo(cache_info->file_semaphore);
4406 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4408 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4409 cache_info->cache_filename);
4410 UnlockSemaphoreInfo(cache_info->file_semaphore);
4411 return(MagickFalse);
4413 if ((cache_info->columns == nexus_info->region.width) &&
4414 (extent <= MagickMaxBufferExtent))
4419 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4420 for (y=0; y < (ssize_t) rows; y++)
4422 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4423 cache_info->number_channels*sizeof(Quantum)+offset*
4424 cache_info->metacontent_extent,length,(unsigned char *) q);
4425 if ((MagickSizeType) count != length)
4427 offset+=cache_info->columns;
4428 q+=cache_info->metacontent_extent*nexus_info->region.width;
4430 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4431 (void) ClosePixelCacheOnDisk(cache_info);
4432 UnlockSemaphoreInfo(cache_info->file_semaphore);
4433 if (y < (ssize_t) rows)
4435 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4436 cache_info->cache_filename);
4437 return(MagickFalse);
4441 case DistributedCache:
4449 if ((cache_info->debug != MagickFalse) &&
4450 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4451 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4452 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4453 nexus_info->region.width,(double) nexus_info->region.height,(double)
4454 nexus_info->region.x,(double) nexus_info->region.y);
4459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4463 + R e a d P i x e l C a c h e P i x e l s %
4467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4469 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4472 % The format of the ReadPixelCachePixels() method is:
4474 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4475 % NexusInfo *nexus_info,ExceptionInfo *exception)
4477 % A description of each parameter follows:
4479 % o cache_info: the pixel cache.
4481 % o nexus_info: the cache nexus to read the pixels.
4483 % o exception: return any errors or warnings in this structure.
4486 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4487 NexusInfo *nexus_info,ExceptionInfo *exception)
4506 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4508 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4509 nexus_info->region.x;
4510 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4512 rows=nexus_info->region.height;
4514 q=nexus_info->pixels;
4515 switch (cache_info->type)
4524 Read pixels from memory.
4526 if ((cache_info->columns == nexus_info->region.width) &&
4527 (extent == (MagickSizeType) ((size_t) extent)))
4532 p=cache_info->pixels+offset*cache_info->number_channels;
4533 for (y=0; y < (ssize_t) rows; y++)
4535 (void) memcpy(q,p,(size_t) length);
4536 p+=cache_info->number_channels*cache_info->columns;
4537 q+=cache_info->number_channels*nexus_info->region.width;
4544 Read pixels from disk.
4546 LockSemaphoreInfo(cache_info->file_semaphore);
4547 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4549 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4550 cache_info->cache_filename);
4551 UnlockSemaphoreInfo(cache_info->file_semaphore);
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 UnlockSemaphoreInfo(cache_info->file_semaphore);
4572 if (y < (ssize_t) rows)
4574 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4575 cache_info->cache_filename);
4576 return(MagickFalse);
4580 case DistributedCache:
4588 if ((cache_info->debug != MagickFalse) &&
4589 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4590 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4591 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4592 nexus_info->region.width,(double) nexus_info->region.height,(double)
4593 nexus_info->region.x,(double) nexus_info->region.y);
4598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4602 + R e f e r e n c e P i x e l C a c h e %
4606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4608 % ReferencePixelCache() increments the reference count associated with the
4609 % pixel cache returning a pointer to the cache.
4611 % The format of the ReferencePixelCache method is:
4613 % Cache ReferencePixelCache(Cache cache_info)
4615 % A description of each parameter follows:
4617 % o cache_info: the pixel cache.
4620 MagickPrivate Cache ReferencePixelCache(Cache cache)
4625 assert(cache != (Cache *) NULL);
4626 cache_info=(CacheInfo *) cache;
4627 assert(cache_info->signature == MagickSignature);
4628 LockSemaphoreInfo(cache_info->semaphore);
4629 cache_info->reference_count++;
4630 UnlockSemaphoreInfo(cache_info->semaphore);
4635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4639 + S e t P i x e l C a c h e M e t h o d s %
4643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4645 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4647 % The format of the SetPixelCacheMethods() method is:
4649 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4651 % A description of each parameter follows:
4653 % o cache: the pixel cache.
4655 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4658 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4663 GetOneAuthenticPixelFromHandler
4664 get_one_authentic_pixel_from_handler;
4666 GetOneVirtualPixelFromHandler
4667 get_one_virtual_pixel_from_handler;
4670 Set cache pixel methods.
4672 assert(cache != (Cache) NULL);
4673 assert(cache_methods != (CacheMethods *) NULL);
4674 cache_info=(CacheInfo *) cache;
4675 assert(cache_info->signature == MagickSignature);
4676 if (cache_info->debug != MagickFalse)
4677 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4678 cache_info->filename);
4679 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4680 cache_info->methods.get_virtual_pixel_handler=
4681 cache_methods->get_virtual_pixel_handler;
4682 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4683 cache_info->methods.destroy_pixel_handler=
4684 cache_methods->destroy_pixel_handler;
4685 if (cache_methods->get_virtual_metacontent_from_handler !=
4686 (GetVirtualMetacontentFromHandler) NULL)
4687 cache_info->methods.get_virtual_metacontent_from_handler=
4688 cache_methods->get_virtual_metacontent_from_handler;
4689 if (cache_methods->get_authentic_pixels_handler !=
4690 (GetAuthenticPixelsHandler) NULL)
4691 cache_info->methods.get_authentic_pixels_handler=
4692 cache_methods->get_authentic_pixels_handler;
4693 if (cache_methods->queue_authentic_pixels_handler !=
4694 (QueueAuthenticPixelsHandler) NULL)
4695 cache_info->methods.queue_authentic_pixels_handler=
4696 cache_methods->queue_authentic_pixels_handler;
4697 if (cache_methods->sync_authentic_pixels_handler !=
4698 (SyncAuthenticPixelsHandler) NULL)
4699 cache_info->methods.sync_authentic_pixels_handler=
4700 cache_methods->sync_authentic_pixels_handler;
4701 if (cache_methods->get_authentic_pixels_from_handler !=
4702 (GetAuthenticPixelsFromHandler) NULL)
4703 cache_info->methods.get_authentic_pixels_from_handler=
4704 cache_methods->get_authentic_pixels_from_handler;
4705 if (cache_methods->get_authentic_metacontent_from_handler !=
4706 (GetAuthenticMetacontentFromHandler) NULL)
4707 cache_info->methods.get_authentic_metacontent_from_handler=
4708 cache_methods->get_authentic_metacontent_from_handler;
4709 get_one_virtual_pixel_from_handler=
4710 cache_info->methods.get_one_virtual_pixel_from_handler;
4711 if (get_one_virtual_pixel_from_handler !=
4712 (GetOneVirtualPixelFromHandler) NULL)
4713 cache_info->methods.get_one_virtual_pixel_from_handler=
4714 cache_methods->get_one_virtual_pixel_from_handler;
4715 get_one_authentic_pixel_from_handler=
4716 cache_methods->get_one_authentic_pixel_from_handler;
4717 if (get_one_authentic_pixel_from_handler !=
4718 (GetOneAuthenticPixelFromHandler) NULL)
4719 cache_info->methods.get_one_authentic_pixel_from_handler=
4720 cache_methods->get_one_authentic_pixel_from_handler;
4724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4728 + S e t P i x e l C a c h e N e x u s P i x e l s %
4732 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4734 % SetPixelCacheNexusPixels() defines the region of the cache for the
4735 % specified cache nexus.
4737 % The format of the SetPixelCacheNexusPixels() method is:
4739 % Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4740 % const RectangleInfo *region,NexusInfo *nexus_info,
4741 % ExceptionInfo *exception)
4743 % A description of each parameter follows:
4745 % o image: the image.
4747 % o mode: ReadMode, WriteMode, or IOMode.
4749 % o region: A pointer to the RectangleInfo structure that defines the
4750 % region of this particular cache nexus.
4752 % o nexus_info: the cache nexus to set.
4754 % o exception: return any errors or warnings in this structure.
4758 static inline MagickBooleanType AcquireCacheNexusPixels(
4759 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4760 ExceptionInfo *exception)
4762 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4763 return(MagickFalse);
4764 nexus_info->mapped=MagickFalse;
4765 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4766 (size_t) nexus_info->length));
4767 if (nexus_info->cache == (Quantum *) NULL)
4769 nexus_info->mapped=MagickTrue;
4770 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4771 nexus_info->length);
4773 if (nexus_info->cache == (Quantum *) NULL)
4775 (void) ThrowMagickException(exception,GetMagickModule(),
4776 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4777 cache_info->filename);
4778 return(MagickFalse);
4783 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4786 if (mode == ReadMode)
4788 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4791 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4794 static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4795 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4807 cache_info=(CacheInfo *) image->cache;
4808 assert(cache_info->signature == MagickSignature);
4809 if (cache_info->type == UndefinedCache)
4810 return((Quantum *) NULL);
4811 nexus_info->region=(*region);
4812 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
4818 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4819 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4820 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4821 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4822 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4823 ((nexus_info->region.width == cache_info->columns) ||
4824 ((nexus_info->region.width % cache_info->columns) == 0)))))
4830 Pixels are accessed directly from memory.
4832 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4833 nexus_info->region.x;
4834 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4836 nexus_info->metacontent=(void *) NULL;
4837 if (cache_info->metacontent_extent != 0)
4838 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4839 offset*cache_info->metacontent_extent;
4840 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4841 return(nexus_info->pixels);
4845 Pixels are stored in a cache region until they are synced to the cache.
4847 number_pixels=(MagickSizeType) nexus_info->region.width*
4848 nexus_info->region.height;
4849 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4850 if (cache_info->metacontent_extent != 0)
4851 length+=number_pixels*cache_info->metacontent_extent;
4852 if (nexus_info->cache == (Quantum *) NULL)
4854 nexus_info->length=length;
4855 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4856 if (status == MagickFalse)
4858 nexus_info->length=0;
4859 return((Quantum *) NULL);
4863 if (nexus_info->length != length)
4865 RelinquishCacheNexusPixels(nexus_info);
4866 nexus_info->length=length;
4867 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4868 if (status == MagickFalse)
4870 nexus_info->length=0;
4871 return((Quantum *) NULL);
4874 nexus_info->pixels=nexus_info->cache;
4875 nexus_info->metacontent=(void *) NULL;
4876 if (cache_info->metacontent_extent != 0)
4877 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
4878 cache_info->number_channels);
4879 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4880 return(nexus_info->pixels);
4884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4888 % 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 %
4892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4894 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4895 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4896 % access that is outside the boundaries of the image cache.
4898 % The format of the SetPixelCacheVirtualMethod() method is:
4900 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4901 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4903 % A description of each parameter follows:
4905 % o image: the image.
4907 % o virtual_pixel_method: choose the type of virtual pixel.
4909 % o exception: return any errors or warnings in this structure.
4913 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
4914 ExceptionInfo *exception)
4928 assert(image != (Image *) NULL);
4929 assert(image->signature == MagickSignature);
4930 if (image->debug != MagickFalse)
4931 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4932 assert(image->cache != (Cache) NULL);
4933 cache_info=(CacheInfo *) image->cache;
4934 assert(cache_info->signature == MagickSignature);
4935 image->alpha_trait=BlendPixelTrait;
4937 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
4938 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4939 #pragma omp parallel for schedule(static,4) shared(status) \
4940 magick_threads(image,image,1,1)
4942 for (y=0; y < (ssize_t) image->rows; y++)
4950 if (status == MagickFalse)
4952 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4953 if (q == (Quantum *) NULL)
4958 for (x=0; x < (ssize_t) image->columns; x++)
4960 SetPixelAlpha(image,alpha,q);
4961 q+=GetPixelChannels(image);
4963 status=SyncCacheViewAuthenticPixels(image_view,exception);
4965 image_view=DestroyCacheView(image_view);
4969 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
4970 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
4978 assert(image != (Image *) NULL);
4979 assert(image->signature == MagickSignature);
4980 if (image->debug != MagickFalse)
4981 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4982 assert(image->cache != (Cache) NULL);
4983 cache_info=(CacheInfo *) image->cache;
4984 assert(cache_info->signature == MagickSignature);
4985 method=cache_info->virtual_pixel_method;
4986 cache_info->virtual_pixel_method=virtual_pixel_method;
4987 if ((image->columns != 0) && (image->rows != 0))
4988 switch (virtual_pixel_method)
4990 case BackgroundVirtualPixelMethod:
4992 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
4993 (image->alpha_trait != BlendPixelTrait))
4994 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
4995 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
4996 (IsGrayColorspace(image->colorspace) != MagickFalse))
4997 (void) TransformImageColorspace(image,RGBColorspace,exception);
5000 case TransparentVirtualPixelMethod:
5002 if (image->alpha_trait != BlendPixelTrait)
5003 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5017 + 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 %
5021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5023 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5024 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5025 % is synced, otherwise MagickFalse.
5027 % The format of the SyncAuthenticPixelCacheNexus() method is:
5029 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5030 % NexusInfo *nexus_info,ExceptionInfo *exception)
5032 % A description of each parameter follows:
5034 % o image: the image.
5036 % o nexus_info: the cache nexus to sync.
5038 % o exception: return any errors or warnings in this structure.
5041 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5042 NexusInfo *nexus_info,ExceptionInfo *exception)
5051 Transfer pixels to the cache.
5053 assert(image != (Image *) NULL);
5054 assert(image->signature == MagickSignature);
5055 if (image->cache == (Cache) NULL)
5056 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5057 cache_info=(CacheInfo *) image->cache;
5058 assert(cache_info->signature == MagickSignature);
5059 if (cache_info->type == UndefinedCache)
5060 return(MagickFalse);
5061 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5063 assert(cache_info->signature == MagickSignature);
5064 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5065 if ((cache_info->metacontent_extent != 0) &&
5066 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5067 return(MagickFalse);
5072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5076 + S y n c A u t h e n t i c P i x e l C a c h e %
5080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5082 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5083 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5084 % otherwise MagickFalse.
5086 % The format of the SyncAuthenticPixelsCache() method is:
5088 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5089 % ExceptionInfo *exception)
5091 % A description of each parameter follows:
5093 % o image: the image.
5095 % o exception: return any errors or warnings in this structure.
5098 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5099 ExceptionInfo *exception)
5105 id = GetOpenMPThreadId();
5110 assert(image != (Image *) NULL);
5111 assert(image->signature == MagickSignature);
5112 assert(image->cache != (Cache) NULL);
5113 cache_info=(CacheInfo *) image->cache;
5114 assert(cache_info->signature == MagickSignature);
5115 assert(id < (int) cache_info->number_threads);
5116 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5126 % S y n c A u t h e n t i c P i x e l s %
5130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5132 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5133 % The method returns MagickTrue if the pixel region is flushed, otherwise
5136 % The format of the SyncAuthenticPixels() method is:
5138 % MagickBooleanType SyncAuthenticPixels(Image *image,
5139 % ExceptionInfo *exception)
5141 % A description of each parameter follows:
5143 % o image: the image.
5145 % o exception: return any errors or warnings in this structure.
5148 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5149 ExceptionInfo *exception)
5155 id = GetOpenMPThreadId();
5160 assert(image != (Image *) NULL);
5161 assert(image->signature == MagickSignature);
5162 assert(image->cache != (Cache) NULL);
5163 cache_info=(CacheInfo *) image->cache;
5164 assert(cache_info->signature == MagickSignature);
5165 if (cache_info->methods.sync_authentic_pixels_handler !=
5166 (SyncAuthenticPixelsHandler) NULL)
5168 status=cache_info->methods.sync_authentic_pixels_handler(image,
5172 assert(id < (int) cache_info->number_threads);
5173 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5183 + S y n c I m a g e P i x e l C a c h e %
5187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5189 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5190 % The method returns MagickTrue if the pixel region is flushed, otherwise
5193 % The format of the SyncImagePixelCache() method is:
5195 % MagickBooleanType SyncImagePixelCache(Image *image,
5196 % ExceptionInfo *exception)
5198 % A description of each parameter follows:
5200 % o image: the image.
5202 % o exception: return any errors or warnings in this structure.
5205 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5206 ExceptionInfo *exception)
5211 assert(image != (Image *) NULL);
5212 assert(exception != (ExceptionInfo *) NULL);
5213 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5214 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5222 + 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 %
5226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5228 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5229 % of the pixel cache.
5231 % The format of the WritePixelCacheMetacontent() method is:
5233 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5234 % NexusInfo *nexus_info,ExceptionInfo *exception)
5236 % A description of each parameter follows:
5238 % o cache_info: the pixel cache.
5240 % o nexus_info: the cache nexus to write the meta-content.
5242 % o exception: return any errors or warnings in this structure.
5245 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5246 NexusInfo *nexus_info,ExceptionInfo *exception)
5256 register const unsigned char
5265 if (cache_info->metacontent_extent == 0)
5266 return(MagickFalse);
5267 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5269 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5270 nexus_info->region.x;
5271 length=(MagickSizeType) nexus_info->region.width*
5272 cache_info->metacontent_extent;
5273 rows=nexus_info->region.height;
5274 extent=(MagickSizeType) length*rows;
5275 p=(unsigned char *) nexus_info->metacontent;
5276 switch (cache_info->type)
5281 register unsigned char
5285 Write associated pixels to memory.
5287 if ((cache_info->columns == nexus_info->region.width) &&
5288 (extent == (MagickSizeType) ((size_t) extent)))
5293 q=(unsigned char *) cache_info->metacontent+offset*
5294 cache_info->metacontent_extent;
5295 for (y=0; y < (ssize_t) rows; y++)
5297 (void) memcpy(q,p,(size_t) length);
5298 p+=nexus_info->region.width*cache_info->metacontent_extent;
5299 q+=cache_info->columns*cache_info->metacontent_extent;
5306 Write associated pixels to disk.
5308 LockSemaphoreInfo(cache_info->file_semaphore);
5309 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5311 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5312 cache_info->cache_filename);
5313 UnlockSemaphoreInfo(cache_info->file_semaphore);
5314 return(MagickFalse);
5316 if ((cache_info->columns == nexus_info->region.width) &&
5317 (extent <= MagickMaxBufferExtent))
5322 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5323 for (y=0; y < (ssize_t) rows; y++)
5325 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5326 cache_info->number_channels*sizeof(Quantum)+offset*
5327 cache_info->metacontent_extent,length,(const unsigned char *) p);
5328 if ((MagickSizeType) count != length)
5330 p+=nexus_info->region.width*cache_info->metacontent_extent;
5331 offset+=cache_info->columns;
5333 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5334 (void) ClosePixelCacheOnDisk(cache_info);
5335 UnlockSemaphoreInfo(cache_info->file_semaphore);
5336 if (y < (ssize_t) rows)
5338 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5339 cache_info->cache_filename);
5340 return(MagickFalse);
5344 case DistributedCache:
5352 if ((cache_info->debug != MagickFalse) &&
5353 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5354 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5355 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5356 nexus_info->region.width,(double) nexus_info->region.height,(double)
5357 nexus_info->region.x,(double) nexus_info->region.y);
5362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5366 + W r i t e C a c h e P i x e l s %
5370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5372 % WritePixelCachePixels() writes image pixels to the specified region of the
5375 % The format of the WritePixelCachePixels() method is:
5377 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5378 % NexusInfo *nexus_info,ExceptionInfo *exception)
5380 % A description of each parameter follows:
5382 % o cache_info: the pixel cache.
5384 % o nexus_info: the cache nexus to write the pixels.
5386 % o exception: return any errors or warnings in this structure.
5389 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5390 NexusInfo *nexus_info,ExceptionInfo *exception)
5400 register const Quantum
5409 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5411 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5412 nexus_info->region.x;
5413 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5415 rows=nexus_info->region.height;
5417 p=nexus_info->pixels;
5418 switch (cache_info->type)
5427 Write pixels to memory.
5429 if ((cache_info->columns == nexus_info->region.width) &&
5430 (extent == (MagickSizeType) ((size_t) extent)))
5435 q=cache_info->pixels+offset*cache_info->number_channels;
5436 for (y=0; y < (ssize_t) rows; y++)
5438 (void) memcpy(q,p,(size_t) length);
5439 p+=nexus_info->region.width*cache_info->number_channels;
5440 q+=cache_info->columns*cache_info->number_channels;
5447 Write pixels to disk.
5449 LockSemaphoreInfo(cache_info->file_semaphore);
5450 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5452 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5453 cache_info->cache_filename);
5454 UnlockSemaphoreInfo(cache_info->file_semaphore);
5455 return(MagickFalse);
5457 if ((cache_info->columns == nexus_info->region.width) &&
5458 (extent <= MagickMaxBufferExtent))
5463 for (y=0; y < (ssize_t) rows; y++)
5465 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5466 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5468 if ((MagickSizeType) count != length)
5470 p+=nexus_info->region.width*cache_info->number_channels;
5471 offset+=cache_info->columns;
5473 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5474 (void) ClosePixelCacheOnDisk(cache_info);
5475 UnlockSemaphoreInfo(cache_info->file_semaphore);
5476 if (y < (ssize_t) rows)
5478 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5479 cache_info->cache_filename);
5480 return(MagickFalse);
5484 case DistributedCache:
5492 if ((cache_info->debug != MagickFalse) &&
5493 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5494 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5495 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5496 nexus_info->region.width,(double) nexus_info->region.height,(double)
5497 nexus_info->region.x,(double) nexus_info->region.y);