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_HAVE_SOCKET)
75 #include <sys/socket.h>
76 #include <netinet/in.h>
77 #include <arpa/inet.h>
79 #if defined(MAGICKCORE_ZLIB_DELEGATE)
86 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
87 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
88 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
93 typedef struct _MagickModulo
123 Forward declarations.
125 #if defined(__cplusplus) || defined(c_plusplus)
130 GetImagePixelCache(Image *,const MagickBooleanType,ExceptionInfo *)
134 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
135 const ssize_t,const size_t,const size_t,ExceptionInfo *),
136 *GetVirtualPixelsCache(const Image *);
139 *GetVirtualMetacontentFromCache(const Image *);
141 static MagickBooleanType
142 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,Quantum *,
144 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
145 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
146 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
147 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
148 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
149 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
150 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
151 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
154 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
155 const size_t,ExceptionInfo *),
156 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
157 const size_t,ExceptionInfo *),
158 *SetPixelCacheNexusPixels(const Image *,const MapMode,const RectangleInfo *,
159 NexusInfo *,ExceptionInfo *) magick_hot_spot;
161 #if defined(__cplusplus) || defined(c_plusplus)
168 static volatile MagickBooleanType
169 instantiate_cache = MagickFalse;
172 *cache_semaphore = (SemaphoreInfo *) NULL;
175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
179 + A c q u i r e P i x e l C a c h e %
183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185 % AcquirePixelCache() acquires a pixel cache.
187 % The format of the AcquirePixelCache() method is:
189 % Cache AcquirePixelCache(const size_t number_threads)
191 % A description of each parameter follows:
193 % o number_threads: the number of nexus threads.
196 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
204 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
205 if (cache_info == (CacheInfo *) NULL)
206 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
207 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
208 cache_info->type=UndefinedCache;
209 cache_info->mode=IOMode;
210 cache_info->colorspace=sRGBColorspace;
211 cache_info->file=(-1);
212 cache_info->id=GetMagickThreadId();
213 cache_info->number_threads=number_threads;
214 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
215 cache_info->number_threads=GetOpenMPMaximumThreads();
216 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
217 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
218 if (cache_info->number_threads == 0)
219 cache_info->number_threads=1;
220 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
221 if (cache_info->nexus_info == (NexusInfo **) NULL)
222 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
223 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
224 if (synchronize != (const char *) NULL)
226 cache_info->synchronize=IsStringTrue(synchronize);
227 synchronize=DestroyString(synchronize);
229 cache_info->semaphore=AllocateSemaphoreInfo();
230 cache_info->reference_count=1;
231 cache_info->file_semaphore=AllocateSemaphoreInfo();
232 cache_info->debug=IsEventLogging();
233 cache_info->signature=MagickSignature;
234 return((Cache ) cache_info);
238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242 % A c q u i r e P i x e l C a c h e N e x u s %
246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
248 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
250 % The format of the AcquirePixelCacheNexus method is:
252 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
254 % A description of each parameter follows:
256 % o number_threads: the number of nexus threads.
259 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
267 nexus_info=(NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(
268 number_threads,sizeof(*nexus_info)));
269 if (nexus_info == (NexusInfo **) NULL)
270 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
271 nexus_info[0]=(NexusInfo *) AcquireQuantumMemory(number_threads,
272 sizeof(**nexus_info));
273 if (nexus_info[0] == (NexusInfo *) NULL)
274 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
275 (void) ResetMagickMemory(nexus_info[0],0,number_threads*sizeof(**nexus_info));
276 for (i=0; i < (ssize_t) number_threads; i++)
278 nexus_info[i]=(&nexus_info[0][i]);
279 nexus_info[i]->signature=MagickSignature;
285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
289 + A c q u i r e P i x e l C a c h e P i x e l s %
293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295 % AcquirePixelCachePixels() returns the pixels associated with the specified
298 % The format of the AcquirePixelCachePixels() method is:
300 % const void *AcquirePixelCachePixels(const Image *image,
301 % MagickSizeType *length,ExceptionInfo *exception)
303 % A description of each parameter follows:
305 % o image: the image.
307 % o length: the pixel cache length.
309 % o exception: return any errors or warnings in this structure.
312 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
313 MagickSizeType *length,ExceptionInfo *exception)
318 assert(image != (const Image *) NULL);
319 assert(image->signature == MagickSignature);
320 assert(exception != (ExceptionInfo *) NULL);
321 assert(exception->signature == MagickSignature);
322 assert(image->cache != (Cache) NULL);
323 cache_info=(CacheInfo *) image->cache;
324 assert(cache_info->signature == MagickSignature);
326 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
327 return((const void *) NULL);
328 *length=cache_info->length;
329 return((const void *) cache_info->pixels);
333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337 + C a c h e C o m p o n e n t G e n e s i s %
341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343 % CacheComponentGenesis() instantiates the cache component.
345 % The format of the CacheComponentGenesis method is:
347 % MagickBooleanType CacheComponentGenesis(void)
350 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
352 AcquireSemaphoreInfo(&cache_semaphore);
357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
361 + C a c h e C o m p o n e n t T e r m i n u s %
365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
367 % CacheComponentTerminus() destroys the cache component.
369 % The format of the CacheComponentTerminus() method is:
371 % CacheComponentTerminus(void)
374 MagickPrivate void CacheComponentTerminus(void)
376 if (cache_semaphore == (SemaphoreInfo *) NULL)
377 AcquireSemaphoreInfo(&cache_semaphore);
378 LockSemaphoreInfo(cache_semaphore);
379 instantiate_cache=MagickFalse;
380 UnlockSemaphoreInfo(cache_semaphore);
381 DestroySemaphoreInfo(&cache_semaphore);
385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389 + C l o n e P i x e l C a c h e %
393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
395 % ClonePixelCache() clones a pixel cache.
397 % The format of the ClonePixelCache() method is:
399 % Cache ClonePixelCache(const Cache cache)
401 % A description of each parameter follows:
403 % o cache: the pixel cache.
406 MagickPrivate Cache ClonePixelCache(const Cache cache)
414 assert(cache != NULL);
415 cache_info=(const CacheInfo *) cache;
416 assert(cache_info->signature == MagickSignature);
417 if (cache_info->debug != MagickFalse)
418 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
419 cache_info->filename);
420 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
421 if (clone_info == (Cache) NULL)
422 return((Cache) NULL);
423 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
424 return((Cache ) clone_info);
428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
432 + C l o n e P i x e l C a c h e P i x e l s %
436 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
437 % ClonePixelCachePixels() clones the source pixel cache to the destination
440 % The format of the ClonePixelCachePixels() method is:
442 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
443 % CacheInfo *source_info,ExceptionInfo *exception)
445 % A description of each parameter follows:
447 % o cache_info: the pixel cache.
449 % o source_info: the source pixel cache.
451 % o exception: return any errors or warnings in this structure.
455 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
461 if (cache_info->file != -1)
463 status=close(cache_info->file);
464 cache_info->file=(-1);
465 RelinquishMagickResource(FileResource,1);
467 return(status == -1 ? MagickFalse : MagickTrue);
470 static inline MagickSizeType MagickMax(const MagickSizeType x,
471 const MagickSizeType y)
478 static inline MagickSizeType MagickMin(const MagickSizeType x,
479 const MagickSizeType y)
486 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
493 Open pixel cache on disk.
495 if (cache_info->file != -1)
496 return(MagickTrue); /* cache already open */
497 if (*cache_info->cache_filename == '\0')
498 file=AcquireUniqueFileResource(cache_info->cache_filename);
504 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
509 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
510 O_BINARY | O_EXCL,S_MODE);
512 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
518 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
521 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
527 (void) AcquireMagickResource(FileResource,1);
528 cache_info->file=file;
529 cache_info->mode=mode;
533 static inline MagickOffsetType ReadPixelCacheRegion(
534 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
535 const MagickSizeType length,unsigned char *restrict buffer)
537 register MagickOffsetType
543 #if !defined(MAGICKCORE_HAVE_PREAD)
544 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
545 return((MagickOffsetType) -1);
548 for (i=0; i < (MagickOffsetType) length; i+=count)
550 #if !defined(MAGICKCORE_HAVE_PREAD)
551 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
552 (MagickSizeType) SSIZE_MAX));
554 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
555 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
567 static inline MagickOffsetType WritePixelCacheRegion(
568 const CacheInfo *restrict cache_info,const MagickOffsetType offset,
569 const MagickSizeType length,const unsigned char *restrict buffer)
571 register MagickOffsetType
577 #if !defined(MAGICKCORE_HAVE_PWRITE)
578 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
579 return((MagickOffsetType) -1);
582 for (i=0; i < (MagickOffsetType) length; i+=count)
584 #if !defined(MAGICKCORE_HAVE_PWRITE)
585 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
586 (MagickSizeType) SSIZE_MAX));
588 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
589 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
601 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
602 CacheInfo *cache_info,ExceptionInfo *exception)
607 register MagickOffsetType
617 Clone pixel cache (both caches on disk).
619 if (cache_info->debug != MagickFalse)
620 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
621 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
623 if (blob == (unsigned char *) NULL)
625 (void) ThrowMagickException(exception,GetMagickModule(),
626 ResourceLimitError,"MemoryAllocationFailed","`%s'",
627 cache_info->filename);
630 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
632 blob=(unsigned char *) RelinquishMagickMemory(blob);
633 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
634 cache_info->cache_filename);
637 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
639 (void) ClosePixelCacheOnDisk(cache_info);
640 blob=(unsigned char *) RelinquishMagickMemory(blob);
641 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
642 clone_info->cache_filename);
646 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
648 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
649 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
653 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
654 cache_info->cache_filename);
657 length=(size_t) count;
658 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
659 if ((MagickSizeType) count != length)
661 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
662 clone_info->cache_filename);
666 (void) ClosePixelCacheOnDisk(clone_info);
667 (void) ClosePixelCacheOnDisk(cache_info);
668 blob=(unsigned char *) RelinquishMagickMemory(blob);
669 if (i < (MagickOffsetType) cache_info->length)
674 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
675 CacheInfo *cache_info,ExceptionInfo *exception)
680 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
683 Clone pixel cache (both caches in memory).
685 if (cache_info->debug != MagickFalse)
686 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
687 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
691 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
694 Clone pixel cache (one cache on disk, one in memory).
696 if (cache_info->debug != MagickFalse)
697 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
698 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
700 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
701 cache_info->cache_filename);
704 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
705 cache_info->length,(unsigned char *) clone_info->pixels);
706 (void) ClosePixelCacheOnDisk(cache_info);
707 if ((MagickSizeType) count != cache_info->length)
709 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
710 cache_info->cache_filename);
715 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
718 Clone pixel cache (one cache on disk, one in memory).
720 if (clone_info->debug != MagickFalse)
721 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
722 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
724 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
725 clone_info->cache_filename);
728 count=WritePixelCacheRegion(clone_info,clone_info->offset,
729 clone_info->length,(unsigned char *) cache_info->pixels);
730 (void) ClosePixelCacheOnDisk(clone_info);
731 if ((MagickSizeType) count != clone_info->length)
733 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
734 clone_info->cache_filename);
740 Clone pixel cache (both caches on disk).
742 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
745 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
746 CacheInfo *cache_info,ExceptionInfo *exception)
759 register unsigned char
772 Clone pixel cache (unoptimized).
774 if (cache_info->debug != MagickFalse)
776 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
777 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
779 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
780 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
782 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
783 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
787 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
788 clone_info->number_channels)*sizeof(Quantum),MagickMax(
789 cache_info->metacontent_extent,clone_info->metacontent_extent));
790 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
791 if (blob == (unsigned char *) NULL)
793 (void) ThrowMagickException(exception,GetMagickModule(),
794 ResourceLimitError,"MemoryAllocationFailed","`%s'",
795 cache_info->filename);
798 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
801 if (cache_info->type == DiskCache)
803 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
805 blob=(unsigned char *) RelinquishMagickMemory(blob);
806 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
807 cache_info->cache_filename);
810 cache_offset=cache_info->offset;
812 if (clone_info->type == DiskCache)
814 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
816 blob=(unsigned char *) RelinquishMagickMemory(blob);
817 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
818 clone_info->cache_filename);
821 clone_offset=clone_info->offset;
824 Clone pixel channels.
828 for (y=0; y < (ssize_t) cache_info->rows; y++)
830 for (x=0; x < (ssize_t) cache_info->columns; x++)
836 Read a set of pixel channels.
838 length=cache_info->number_channels*sizeof(Quantum);
839 if (cache_info->type != DiskCache)
840 p=(unsigned char *) cache_info->pixels+cache_offset;
843 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
844 if ((MagickSizeType) count != length)
850 cache_offset+=length;
851 if ((y < (ssize_t) clone_info->rows) &&
852 (x < (ssize_t) clone_info->columns))
853 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
865 Write a set of pixel channels.
867 channel=clone_info->channel_map[i].channel;
868 traits=cache_info->channel_map[channel].traits;
869 if (traits == UndefinedPixelTrait)
871 clone_offset+=sizeof(Quantum);
874 offset=cache_info->channel_map[channel].offset;
875 if (clone_info->type != DiskCache)
876 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
877 offset*sizeof(Quantum),sizeof(Quantum));
880 count=WritePixelCacheRegion(clone_info,clone_offset,
881 sizeof(Quantum),p+offset*sizeof(Quantum));
882 if ((MagickSizeType) count != sizeof(Quantum))
888 clone_offset+=sizeof(Quantum);
891 if (y < (ssize_t) clone_info->rows)
894 Set remaining columns as undefined.
896 length=clone_info->number_channels*sizeof(Quantum);
897 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
898 for ( ; x < (ssize_t) clone_info->columns; x++)
900 if (clone_info->type != DiskCache)
901 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
905 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
906 if ((MagickSizeType) count != length)
912 clone_offset+=length;
916 length=clone_info->number_channels*sizeof(Quantum);
917 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
918 for ( ; y < (ssize_t) clone_info->rows; y++)
921 Set remaining rows as undefined.
923 for (x=0; x < (ssize_t) clone_info->columns; x++)
925 if (clone_info->type != DiskCache)
926 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
930 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
931 if ((MagickSizeType) count != length)
937 clone_offset+=length;
940 if ((cache_info->metacontent_extent != 0) ||
941 (clone_info->metacontent_extent != 0))
946 for (y=0; y < (ssize_t) cache_info->rows; y++)
948 for (x=0; x < (ssize_t) cache_info->columns; x++)
951 Read a set of metacontent.
953 length=cache_info->metacontent_extent;
954 if (cache_info->type != DiskCache)
955 p=(unsigned char *) cache_info->pixels+cache_offset;
958 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
959 if ((MagickSizeType) count != length)
965 cache_offset+=length;
966 if ((y < (ssize_t) clone_info->rows) &&
967 (x < (ssize_t) clone_info->columns))
970 Write a set of metacontent.
972 length=clone_info->metacontent_extent;
973 if (clone_info->type != DiskCache)
974 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
978 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
979 if ((MagickSizeType) count != length)
985 clone_offset+=length;
988 length=clone_info->metacontent_extent;
989 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
990 for ( ; x < (ssize_t) clone_info->columns; x++)
993 Set remaining columns as undefined.
995 if (clone_info->type != DiskCache)
996 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1000 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1001 if ((MagickSizeType) count != length)
1007 clone_offset+=length;
1010 if (y < (ssize_t) clone_info->rows)
1013 Set remaining rows as undefined.
1015 length=clone_info->metacontent_extent;
1016 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1017 for ( ; y < (ssize_t) clone_info->rows; y++)
1019 for (x=0; x < (ssize_t) clone_info->columns; x++)
1021 if (clone_info->type != DiskCache)
1022 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1026 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1028 if ((MagickSizeType) count != length)
1034 clone_offset+=length;
1039 if (clone_info->type == DiskCache)
1040 (void) ClosePixelCacheOnDisk(clone_info);
1041 if (cache_info->type == DiskCache)
1042 (void) ClosePixelCacheOnDisk(cache_info);
1043 blob=(unsigned char *) RelinquishMagickMemory(blob);
1047 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1048 CacheInfo *cache_info,ExceptionInfo *exception)
1054 if (cache_info->type == PingCache)
1056 p=cache_info->channel_map;
1057 q=clone_info->channel_map;
1058 if ((cache_info->columns == clone_info->columns) &&
1059 (cache_info->rows == clone_info->rows) &&
1060 (cache_info->number_channels == clone_info->number_channels) &&
1061 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1062 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1063 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1064 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1072 + C l o n e P i x e l C a c h e M e t h o d s %
1076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1081 % The format of the ClonePixelCacheMethods() method is:
1083 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1085 % A description of each parameter follows:
1087 % o clone: Specifies a pointer to a Cache structure.
1089 % o cache: the pixel cache.
1092 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1098 assert(clone != (Cache) NULL);
1099 source_info=(CacheInfo *) clone;
1100 assert(source_info->signature == MagickSignature);
1101 if (source_info->debug != MagickFalse)
1102 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1103 source_info->filename);
1104 assert(cache != (Cache) NULL);
1105 cache_info=(CacheInfo *) cache;
1106 assert(cache_info->signature == MagickSignature);
1107 source_info->methods=cache_info->methods;
1111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1115 + D i s t r i b u t e d P i x e l C a c h e %
1119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1121 % DistributedPixelCache() waits on the specified port for commands to
1122 % create, read, update, or destroy a pixel cache.
1124 % The format of the DistributedPixelCache() method is:
1126 % void DistributedPixelCache(const size_t port)
1128 % A description of each parameter follows:
1130 % o port: connect the distributed pixel cache at this port.
1133 MagickExport void DistributedPixelCache(const size_t port)
1135 #if defined(MAGICKCORE_HAVE_SOCKET)
1137 buffer[MaxTextExtent];
1154 cache_socket=socket(AF_INET,SOCK_STREAM,0);
1155 if (cache_socket == -1)
1157 perror("Distributed pixel cache: server socket");
1161 status=setsockopt(cache_socket,SOL_SOCKET,SO_REUSEADDR,&one,(socklen_t)
1165 perror("Distributed pixel cache: server setsockopt");
1168 (void) ResetMagickMemory(&address,0,sizeof(address));
1169 address.sin_family=AF_INET;
1170 address.sin_port=htons(port);
1171 address.sin_addr.s_addr=INADDR_ANY;
1172 status=bind(cache_socket,(struct sockaddr *) &address,(socklen_t)
1176 perror("Distributed pixel cache: server bind");
1179 status=listen(cache_socket,5);
1182 perror("Distributed pixel cache: server listen");
1185 (void) fprintf(stdout,
1186 "Distributed pixel cache server: waiting for client on port %d\n",(int)
1188 (void) fflush(stdout);
1191 length=(socklen_t) sizeof(address);
1192 cache_client=accept(cache_socket,(struct sockaddr *) &address,&length);
1193 (void) fprintf(stdout,"Connection from (%s, %d)\n",
1194 inet_ntoa(address.sin_addr),(int) ntohs(address.sin_port));
1195 count=recv(cache_client,buffer,1,0);
1237 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
1238 "DelegateLibrarySupportNotBuiltIn","'%s' (socket)",image_info->filename);
1243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1247 + D e s t r o y I m a g e P i x e l C a c h e %
1251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1253 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1255 % The format of the DestroyImagePixelCache() method is:
1257 % void DestroyImagePixelCache(Image *image)
1259 % A description of each parameter follows:
1261 % o image: the image.
1264 static void DestroyImagePixelCache(Image *image)
1266 assert(image != (Image *) NULL);
1267 assert(image->signature == MagickSignature);
1268 if (image->debug != MagickFalse)
1269 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1270 if (image->cache == (void *) NULL)
1272 image->cache=DestroyPixelCache(image->cache);
1276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1280 + D e s t r o y I m a g e P i x e l s %
1284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1286 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1288 % The format of the DestroyImagePixels() method is:
1290 % void DestroyImagePixels(Image *image)
1292 % A description of each parameter follows:
1294 % o image: the image.
1297 MagickExport void DestroyImagePixels(Image *image)
1302 assert(image != (const Image *) NULL);
1303 assert(image->signature == MagickSignature);
1304 if (image->debug != MagickFalse)
1305 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1306 assert(image->cache != (Cache) NULL);
1307 cache_info=(CacheInfo *) image->cache;
1308 assert(cache_info->signature == MagickSignature);
1309 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1311 cache_info->methods.destroy_pixel_handler(image);
1314 image->cache=DestroyPixelCache(image->cache);
1318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1322 + D e s t r o y P i x e l C a c h e %
1326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1328 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1330 % The format of the DestroyPixelCache() method is:
1332 % Cache DestroyPixelCache(Cache cache)
1334 % A description of each parameter follows:
1336 % o cache: the pixel cache.
1340 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1342 switch (cache_info->type)
1346 if (cache_info->mapped == MagickFalse)
1347 cache_info->pixels=(Quantum *) RelinquishAlignedMemory(
1348 cache_info->pixels);
1350 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1351 (size_t) cache_info->length);
1352 RelinquishMagickResource(MemoryResource,cache_info->length);
1357 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1358 cache_info->length);
1359 if (cache_info->mode != ReadMode)
1360 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1361 *cache_info->cache_filename='\0';
1362 RelinquishMagickResource(MapResource,cache_info->length);
1366 if (cache_info->file != -1)
1367 (void) ClosePixelCacheOnDisk(cache_info);
1368 if (cache_info->mode != ReadMode)
1369 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1370 *cache_info->cache_filename='\0';
1371 RelinquishMagickResource(DiskResource,cache_info->length);
1374 case DistributedCache:
1382 cache_info->type=UndefinedCache;
1383 cache_info->mapped=MagickFalse;
1384 cache_info->metacontent=(void *) NULL;
1387 MagickPrivate Cache DestroyPixelCache(Cache cache)
1392 assert(cache != (Cache) NULL);
1393 cache_info=(CacheInfo *) cache;
1394 assert(cache_info->signature == MagickSignature);
1395 if (cache_info->debug != MagickFalse)
1396 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1397 cache_info->filename);
1398 LockSemaphoreInfo(cache_info->semaphore);
1399 cache_info->reference_count--;
1400 if (cache_info->reference_count != 0)
1402 UnlockSemaphoreInfo(cache_info->semaphore);
1403 return((Cache) NULL);
1405 UnlockSemaphoreInfo(cache_info->semaphore);
1406 if (cache_info->debug != MagickFalse)
1409 message[MaxTextExtent];
1411 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1412 cache_info->filename);
1413 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1415 RelinquishPixelCachePixels(cache_info);
1416 if (cache_info->nexus_info != (NexusInfo **) NULL)
1417 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1418 cache_info->number_threads);
1419 if (cache_info->random_info != (RandomInfo *) NULL)
1420 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1421 if (cache_info->file_semaphore != (SemaphoreInfo *) NULL)
1422 DestroySemaphoreInfo(&cache_info->file_semaphore);
1423 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1424 DestroySemaphoreInfo(&cache_info->semaphore);
1425 cache_info->signature=(~MagickSignature);
1426 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1436 + D e s t r o y P i x e l C a c h e N e x u s %
1440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1442 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1444 % The format of the DestroyPixelCacheNexus() method is:
1446 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1447 % const size_t number_threads)
1449 % A description of each parameter follows:
1451 % o nexus_info: the nexus to destroy.
1453 % o number_threads: the number of nexus threads.
1457 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1459 if (nexus_info->mapped == MagickFalse)
1460 (void) RelinquishAlignedMemory(nexus_info->cache);
1462 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1463 nexus_info->cache=(Quantum *) NULL;
1464 nexus_info->pixels=(Quantum *) NULL;
1465 nexus_info->metacontent=(void *) NULL;
1466 nexus_info->length=0;
1467 nexus_info->mapped=MagickFalse;
1470 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1471 const size_t number_threads)
1476 assert(nexus_info != (NexusInfo **) NULL);
1477 for (i=0; i < (ssize_t) number_threads; i++)
1479 if (nexus_info[i]->cache != (Quantum *) NULL)
1480 RelinquishCacheNexusPixels(nexus_info[i]);
1481 nexus_info[i]->signature=(~MagickSignature);
1483 nexus_info[0]=(NexusInfo *) RelinquishMagickMemory(nexus_info[0]);
1484 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1493 % G e t A u t h e n t i c M e t a c o n t e n t %
1497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1499 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1500 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1501 % returned if the associated pixels are not available.
1503 % The format of the GetAuthenticMetacontent() method is:
1505 % void *GetAuthenticMetacontent(const Image *image)
1507 % A description of each parameter follows:
1509 % o image: the image.
1512 MagickExport void *GetAuthenticMetacontent(const Image *image)
1518 id = GetOpenMPThreadId();
1523 assert(image != (const Image *) NULL);
1524 assert(image->signature == MagickSignature);
1525 assert(image->cache != (Cache) NULL);
1526 cache_info=(CacheInfo *) image->cache;
1527 assert(cache_info->signature == MagickSignature);
1528 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1529 (GetAuthenticMetacontentFromHandler) NULL)
1531 metacontent=cache_info->methods.
1532 get_authentic_metacontent_from_handler(image);
1533 return(metacontent);
1535 assert(id < (int) cache_info->number_threads);
1536 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1537 cache_info->nexus_info[id]);
1538 return(metacontent);
1542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546 + 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 %
1550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1552 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1553 % with the last call to QueueAuthenticPixelsCache() or
1554 % GetAuthenticPixelsCache().
1556 % The format of the GetAuthenticMetacontentFromCache() method is:
1558 % void *GetAuthenticMetacontentFromCache(const Image *image)
1560 % A description of each parameter follows:
1562 % o image: the image.
1565 static void *GetAuthenticMetacontentFromCache(const Image *image)
1571 id = GetOpenMPThreadId();
1576 assert(image != (const Image *) NULL);
1577 assert(image->signature == MagickSignature);
1578 assert(image->cache != (Cache) NULL);
1579 cache_info=(CacheInfo *) image->cache;
1580 assert(cache_info->signature == MagickSignature);
1581 assert(id < (int) cache_info->number_threads);
1582 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1583 cache_info->nexus_info[id]);
1584 return(metacontent);
1588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1592 + 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 %
1596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1599 % disk pixel cache as defined by the geometry parameters. A pointer to the
1600 % pixels is returned if the pixels are transferred, otherwise a NULL is
1603 % The format of the GetAuthenticPixelCacheNexus() method is:
1605 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1606 % const ssize_t y,const size_t columns,const size_t rows,
1607 % NexusInfo *nexus_info,ExceptionInfo *exception)
1609 % A description of each parameter follows:
1611 % o image: the image.
1613 % o x,y,columns,rows: These values define the perimeter of a region of
1616 % o nexus_info: the cache nexus to return.
1618 % o exception: return any errors or warnings in this structure.
1622 static inline MagickBooleanType IsPixelAuthentic(
1623 const CacheInfo *restrict cache_info,const NexusInfo *restrict nexus_info)
1631 if (cache_info->type == PingCache)
1633 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1634 nexus_info->region.x;
1635 status=nexus_info->pixels == (cache_info->pixels+offset*
1636 cache_info->number_channels) ? MagickTrue : MagickFalse;
1640 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1641 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1642 NexusInfo *nexus_info,ExceptionInfo *exception)
1651 Transfer pixels from the cache.
1653 assert(image != (Image *) NULL);
1654 assert(image->signature == MagickSignature);
1655 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,nexus_info,
1657 if (q == (Quantum *) NULL)
1658 return((Quantum *) NULL);
1659 cache_info=(CacheInfo *) image->cache;
1660 assert(cache_info->signature == MagickSignature);
1661 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1663 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1664 return((Quantum *) NULL);
1665 if (cache_info->metacontent_extent != 0)
1666 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1667 return((Quantum *) NULL);
1672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1676 + 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 %
1680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1682 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1683 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1685 % The format of the GetAuthenticPixelsFromCache() method is:
1687 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1689 % A description of each parameter follows:
1691 % o image: the image.
1694 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1700 id = GetOpenMPThreadId();
1702 assert(image != (const Image *) NULL);
1703 assert(image->signature == MagickSignature);
1704 assert(image->cache != (Cache) NULL);
1705 cache_info=(CacheInfo *) image->cache;
1706 assert(cache_info->signature == MagickSignature);
1707 assert(id < (int) cache_info->number_threads);
1708 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716 % G e t A u t h e n t i c P i x e l Q u e u e %
1720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1722 % GetAuthenticPixelQueue() returns the authentic pixels associated
1723 % corresponding with the last call to QueueAuthenticPixels() or
1724 % GetAuthenticPixels().
1726 % The format of the GetAuthenticPixelQueue() method is:
1728 % Quantum *GetAuthenticPixelQueue(const Image image)
1730 % A description of each parameter follows:
1732 % o image: the image.
1735 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1741 id = GetOpenMPThreadId();
1743 assert(image != (const Image *) NULL);
1744 assert(image->signature == MagickSignature);
1745 assert(image->cache != (Cache) NULL);
1746 cache_info=(CacheInfo *) image->cache;
1747 assert(cache_info->signature == MagickSignature);
1748 if (cache_info->methods.get_authentic_pixels_from_handler !=
1749 (GetAuthenticPixelsFromHandler) NULL)
1750 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1751 assert(id < (int) cache_info->number_threads);
1752 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760 % G e t A u t h e n t i c P i x e l s %
1763 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1766 % region is successfully accessed, a pointer to a Quantum array
1767 % representing the region is returned, otherwise NULL is returned.
1769 % The returned pointer may point to a temporary working copy of the pixels
1770 % or it may point to the original pixels in memory. Performance is maximized
1771 % if the selected region is part of one row, or one or more full rows, since
1772 % then there is opportunity to access the pixels in-place (without a copy)
1773 % if the image is in memory, or in a memory-mapped file. The returned pointer
1774 % must *never* be deallocated by the user.
1776 % Pixels accessed via the returned pointer represent a simple array of type
1777 % Quantum. If the image has corresponding metacontent,call
1778 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1779 % meta-content corresponding to the region. Once the Quantum array has
1780 % been updated, the changes must be saved back to the underlying image using
1781 % SyncAuthenticPixels() or they may be lost.
1783 % The format of the GetAuthenticPixels() method is:
1785 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1786 % const ssize_t y,const size_t columns,const size_t rows,
1787 % ExceptionInfo *exception)
1789 % A description of each parameter follows:
1791 % o image: the image.
1793 % o x,y,columns,rows: These values define the perimeter of a region of
1796 % o exception: return any errors or warnings in this structure.
1799 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1800 const ssize_t y,const size_t columns,const size_t rows,
1801 ExceptionInfo *exception)
1807 id = GetOpenMPThreadId();
1812 assert(image != (Image *) NULL);
1813 assert(image->signature == MagickSignature);
1814 assert(image->cache != (Cache) NULL);
1815 cache_info=(CacheInfo *) image->cache;
1816 assert(cache_info->signature == MagickSignature);
1817 if (cache_info->methods.get_authentic_pixels_handler !=
1818 (GetAuthenticPixelsHandler) NULL)
1820 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1824 assert(id < (int) cache_info->number_threads);
1825 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1826 cache_info->nexus_info[id],exception);
1831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1835 + G e t A u t h e n t i c P i x e l s C a c h e %
1839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1841 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1842 % as defined by the geometry parameters. A pointer to the pixels is returned
1843 % if the pixels are transferred, otherwise a NULL is returned.
1845 % The format of the GetAuthenticPixelsCache() method is:
1847 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1848 % const ssize_t y,const size_t columns,const size_t rows,
1849 % ExceptionInfo *exception)
1851 % A description of each parameter follows:
1853 % o image: the image.
1855 % o x,y,columns,rows: These values define the perimeter of a region of
1858 % o exception: return any errors or warnings in this structure.
1861 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1862 const ssize_t y,const size_t columns,const size_t rows,
1863 ExceptionInfo *exception)
1869 id = GetOpenMPThreadId();
1874 assert(image != (const Image *) NULL);
1875 assert(image->signature == MagickSignature);
1876 assert(image->cache != (Cache) NULL);
1877 cache_info=(CacheInfo *) image->cache;
1878 if (cache_info == (Cache) NULL)
1879 return((Quantum *) NULL);
1880 assert(cache_info->signature == MagickSignature);
1881 assert(id < (int) cache_info->number_threads);
1882 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1883 cache_info->nexus_info[id],exception);
1888 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1892 + G e t I m a g e E x t e n t %
1896 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1898 % GetImageExtent() returns the extent of the pixels associated corresponding
1899 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1901 % The format of the GetImageExtent() method is:
1903 % MagickSizeType GetImageExtent(const Image *image)
1905 % A description of each parameter follows:
1907 % o image: the image.
1910 MagickExport MagickSizeType GetImageExtent(const Image *image)
1916 id = GetOpenMPThreadId();
1918 assert(image != (Image *) NULL);
1919 assert(image->signature == MagickSignature);
1920 if (image->debug != MagickFalse)
1921 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1922 assert(image->cache != (Cache) NULL);
1923 cache_info=(CacheInfo *) image->cache;
1924 assert(cache_info->signature == MagickSignature);
1925 assert(id < (int) cache_info->number_threads);
1926 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1934 + G e t I m a g e P i x e l C a c h e %
1938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1940 % GetImagePixelCache() ensures that there is only a single reference to the
1941 % pixel cache to be modified, updating the provided cache pointer to point to
1942 % a clone of the original pixel cache if necessary.
1944 % The format of the GetImagePixelCache method is:
1946 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1947 % ExceptionInfo *exception)
1949 % A description of each parameter follows:
1951 % o image: the image.
1953 % o clone: any value other than MagickFalse clones the cache pixels.
1955 % o exception: return any errors or warnings in this structure.
1959 static inline MagickBooleanType ValidatePixelCacheMorphology(
1960 const Image *restrict image)
1963 *restrict cache_info;
1965 const PixelChannelMap
1970 Does the image match the pixel cache morphology?
1972 cache_info=(CacheInfo *) image->cache;
1973 p=image->channel_map;
1974 q=cache_info->channel_map;
1975 if ((image->storage_class != cache_info->storage_class) ||
1976 (image->colorspace != cache_info->colorspace) ||
1977 (image->alpha_trait != cache_info->alpha_trait) ||
1978 (image->mask != cache_info->mask) ||
1979 (image->columns != cache_info->columns) ||
1980 (image->rows != cache_info->rows) ||
1981 (image->number_channels != cache_info->number_channels) ||
1982 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
1983 (image->metacontent_extent != cache_info->metacontent_extent) ||
1984 (cache_info->nexus_info == (NexusInfo **) NULL))
1985 return(MagickFalse);
1989 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1990 ExceptionInfo *exception)
1999 static MagickSizeType
2005 cache_timestamp = 0;
2008 LockSemaphoreInfo(image->semaphore);
2009 if (cpu_throttle == 0)
2015 Set CPU throttle in milleseconds.
2017 cpu_throttle=MagickResourceInfinity;
2018 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2019 if (limit == (char *) NULL)
2020 limit=GetPolicyValue("throttle");
2021 if (limit != (char *) NULL)
2023 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2024 limit=DestroyString(limit);
2027 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2028 MagickDelay(cpu_throttle);
2029 if (time_limit == 0)
2032 Set the expire time in seconds.
2034 time_limit=GetMagickResourceLimit(TimeResource);
2035 cache_timestamp=time((time_t *) NULL);
2037 if ((time_limit != MagickResourceInfinity) &&
2038 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
2039 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2040 assert(image->cache != (Cache) NULL);
2041 cache_info=(CacheInfo *) image->cache;
2042 destroy=MagickFalse;
2043 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2045 LockSemaphoreInfo(cache_info->semaphore);
2046 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2057 clone_image=(*image);
2058 clone_image.semaphore=AllocateSemaphoreInfo();
2059 clone_image.reference_count=1;
2060 clone_image.cache=ClonePixelCache(cache_info);
2061 clone_info=(CacheInfo *) clone_image.cache;
2062 status=OpenPixelCache(&clone_image,IOMode,exception);
2063 if (status != MagickFalse)
2065 if (clone != MagickFalse)
2066 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2067 if (status != MagickFalse)
2069 if (cache_info->reference_count == 1)
2070 cache_info->nexus_info=(NexusInfo **) NULL;
2072 image->cache=clone_image.cache;
2075 DestroySemaphoreInfo(&clone_image.semaphore);
2077 UnlockSemaphoreInfo(cache_info->semaphore);
2079 if (destroy != MagickFalse)
2080 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2081 if (status != MagickFalse)
2084 Ensure the image matches the pixel cache morphology.
2086 image->taint=MagickTrue;
2087 image->type=UndefinedType;
2088 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2090 status=OpenPixelCache(image,IOMode,exception);
2091 cache_info=(CacheInfo *) image->cache;
2092 if (cache_info->type == DiskCache)
2093 (void) ClosePixelCacheOnDisk(cache_info);
2096 UnlockSemaphoreInfo(image->semaphore);
2097 if (status == MagickFalse)
2098 return((Cache) NULL);
2099 return(image->cache);
2103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2107 + G e t I m a g e P i x e l C a c h e T y p e %
2111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2113 % GetImagePixelCacheType() returns the pixel cache type: UndefinedCache,
2114 % DiskCache, MemoryCache, MapCache, or PingCache.
2116 % The format of the GetImagePixelCacheType() method is:
2118 % CacheType GetImagePixelCacheType(const Image *image)
2120 % A description of each parameter follows:
2122 % o image: the image.
2125 MagickExport CacheType GetImagePixelCacheType(const Image *image)
2130 assert(image != (Image *) NULL);
2131 assert(image->signature == MagickSignature);
2132 assert(image->cache != (Cache) NULL);
2133 cache_info=(CacheInfo *) image->cache;
2134 assert(cache_info->signature == MagickSignature);
2135 return(cache_info->type);
2139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2143 % G e t O n e A u t h e n t i c P i x e l %
2147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2149 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2150 % location. The image background color is returned if an error occurs.
2152 % The format of the GetOneAuthenticPixel() method is:
2154 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2155 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2157 % A description of each parameter follows:
2159 % o image: the image.
2161 % o x,y: These values define the location of the pixel to return.
2163 % o pixel: return a pixel at the specified (x,y) location.
2165 % o exception: return any errors or warnings in this structure.
2168 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2169 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2180 assert(image != (Image *) NULL);
2181 assert(image->signature == MagickSignature);
2182 assert(image->cache != (Cache) NULL);
2183 cache_info=(CacheInfo *) image->cache;
2184 assert(cache_info->signature == MagickSignature);
2185 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2186 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2187 (GetOneAuthenticPixelFromHandler) NULL)
2188 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2190 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2191 if (q == (Quantum *) NULL)
2193 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2194 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2195 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2196 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2197 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2198 return(MagickFalse);
2200 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2205 channel=GetPixelChannelChannel(image,i);
2206 pixel[channel]=q[i];
2212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2216 + 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 %
2220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2222 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2223 % location. The image background color is returned if an error occurs.
2225 % The format of the GetOneAuthenticPixelFromCache() method is:
2227 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2228 % const ssize_t x,const ssize_t y,Quantum *pixel,
2229 % ExceptionInfo *exception)
2231 % A description of each parameter follows:
2233 % o image: the image.
2235 % o x,y: These values define the location of the pixel to return.
2237 % o pixel: return a pixel at the specified (x,y) location.
2239 % o exception: return any errors or warnings in this structure.
2242 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2243 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2249 id = GetOpenMPThreadId();
2257 assert(image != (const Image *) NULL);
2258 assert(image->signature == MagickSignature);
2259 assert(image->cache != (Cache) NULL);
2260 cache_info=(CacheInfo *) image->cache;
2261 assert(cache_info->signature == MagickSignature);
2262 assert(id < (int) cache_info->number_threads);
2263 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2264 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2266 if (q == (Quantum *) NULL)
2268 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2269 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2270 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2271 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2272 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2273 return(MagickFalse);
2275 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2280 channel=GetPixelChannelChannel(image,i);
2281 pixel[channel]=q[i];
2287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2291 % G e t O n e V i r t u a l P i x e l %
2295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2297 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2298 % (x,y) location. The image background color is returned if an error occurs.
2299 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2301 % The format of the GetOneVirtualPixel() method is:
2303 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2304 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2306 % A description of each parameter follows:
2308 % o image: the image.
2310 % o x,y: These values define the location of the pixel to return.
2312 % o pixel: return a pixel at the specified (x,y) location.
2314 % o exception: return any errors or warnings in this structure.
2317 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2318 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2324 id = GetOpenMPThreadId();
2332 assert(image != (const Image *) NULL);
2333 assert(image->signature == MagickSignature);
2334 assert(image->cache != (Cache) NULL);
2335 cache_info=(CacheInfo *) image->cache;
2336 assert(cache_info->signature == MagickSignature);
2337 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2338 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2339 (GetOneVirtualPixelFromHandler) NULL)
2340 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2341 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2342 assert(id < (int) cache_info->number_threads);
2343 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2344 1UL,1UL,cache_info->nexus_info[id],exception);
2345 if (p == (const Quantum *) NULL)
2347 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2348 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2349 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2350 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2351 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2352 return(MagickFalse);
2354 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2359 channel=GetPixelChannelChannel(image,i);
2360 pixel[channel]=p[i];
2366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2370 + 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 %
2374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2376 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2377 % specified (x,y) location. The image background color is returned if an
2380 % The format of the GetOneVirtualPixelFromCache() method is:
2382 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2383 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2384 % Quantum *pixel,ExceptionInfo *exception)
2386 % A description of each parameter follows:
2388 % o image: the image.
2390 % o virtual_pixel_method: the virtual pixel method.
2392 % o x,y: These values define the location of the pixel to return.
2394 % o pixel: return a pixel at the specified (x,y) location.
2396 % o exception: return any errors or warnings in this structure.
2399 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2400 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2401 Quantum *pixel,ExceptionInfo *exception)
2407 id = GetOpenMPThreadId();
2415 assert(image != (const Image *) NULL);
2416 assert(image->signature == MagickSignature);
2417 assert(image->cache != (Cache) NULL);
2418 cache_info=(CacheInfo *) image->cache;
2419 assert(cache_info->signature == MagickSignature);
2420 assert(id < (int) cache_info->number_threads);
2421 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2422 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2423 cache_info->nexus_info[id],exception);
2424 if (p == (const Quantum *) NULL)
2426 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2427 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2428 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2429 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2430 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2431 return(MagickFalse);
2433 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2438 channel=GetPixelChannelChannel(image,i);
2439 pixel[channel]=p[i];
2445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2449 % G e t O n e V i r t u a l P i x e l I n f o %
2453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2455 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2456 % location. The image background color is returned if an error occurs. If
2457 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2459 % The format of the GetOneVirtualPixelInfo() method is:
2461 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2462 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2463 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2465 % A description of each parameter follows:
2467 % o image: the image.
2469 % o virtual_pixel_method: the virtual pixel method.
2471 % o x,y: these values define the location of the pixel to return.
2473 % o pixel: return a pixel at the specified (x,y) location.
2475 % o exception: return any errors or warnings in this structure.
2478 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2479 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2480 PixelInfo *pixel,ExceptionInfo *exception)
2486 id = GetOpenMPThreadId();
2488 register const Quantum
2491 assert(image != (const Image *) NULL);
2492 assert(image->signature == MagickSignature);
2493 assert(image->cache != (Cache) NULL);
2494 cache_info=(CacheInfo *) image->cache;
2495 assert(cache_info->signature == MagickSignature);
2496 assert(id < (int) cache_info->number_threads);
2497 GetPixelInfo(image,pixel);
2498 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2499 cache_info->nexus_info[id],exception);
2500 if (p == (const Quantum *) NULL)
2501 return(MagickFalse);
2502 GetPixelInfoPixel(image,p,pixel);
2507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2511 + G e t P i x e l C a c h e C o l o r s p a c e %
2515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2517 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2519 % The format of the GetPixelCacheColorspace() method is:
2521 % Colorspace GetPixelCacheColorspace(Cache cache)
2523 % A description of each parameter follows:
2525 % o cache: the pixel cache.
2528 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2533 assert(cache != (Cache) NULL);
2534 cache_info=(CacheInfo *) cache;
2535 assert(cache_info->signature == MagickSignature);
2536 if (cache_info->debug != MagickFalse)
2537 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2538 cache_info->filename);
2539 return(cache_info->colorspace);
2543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2547 + G e t P i x e l C a c h e M e t h o d s %
2551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2553 % GetPixelCacheMethods() initializes the CacheMethods structure.
2555 % The format of the GetPixelCacheMethods() method is:
2557 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2559 % A description of each parameter follows:
2561 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2564 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2566 assert(cache_methods != (CacheMethods *) NULL);
2567 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2568 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2569 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2570 cache_methods->get_virtual_metacontent_from_handler=
2571 GetVirtualMetacontentFromCache;
2572 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2573 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2574 cache_methods->get_authentic_metacontent_from_handler=
2575 GetAuthenticMetacontentFromCache;
2576 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2577 cache_methods->get_one_authentic_pixel_from_handler=
2578 GetOneAuthenticPixelFromCache;
2579 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2580 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2581 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2589 + G e t P i x e l C a c h e N e x u s E x t e n t %
2593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2595 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2596 % corresponding with the last call to SetPixelCacheNexusPixels() or
2597 % GetPixelCacheNexusPixels().
2599 % The format of the GetPixelCacheNexusExtent() method is:
2601 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2602 % NexusInfo *nexus_info)
2604 % A description of each parameter follows:
2606 % o nexus_info: the nexus info.
2609 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2610 NexusInfo *nexus_info)
2618 assert(cache != NULL);
2619 cache_info=(CacheInfo *) cache;
2620 assert(cache_info->signature == MagickSignature);
2621 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2623 return((MagickSizeType) cache_info->columns*cache_info->rows);
2628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2632 + 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 %
2636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2638 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2641 % The format of the GetPixelCacheNexusMetacontent() method is:
2643 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2644 % NexusInfo *nexus_info)
2646 % A description of each parameter follows:
2648 % o cache: the pixel cache.
2650 % o nexus_info: the cache nexus to return the meta-content.
2653 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2654 NexusInfo *nexus_info)
2659 assert(cache != NULL);
2660 cache_info=(CacheInfo *) cache;
2661 assert(cache_info->signature == MagickSignature);
2662 if (cache_info->storage_class == UndefinedClass)
2663 return((void *) NULL);
2664 return(nexus_info->metacontent);
2668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2672 + G e t P i x e l C a c h e N e x u s P i x e l s %
2676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2678 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2681 % The format of the GetPixelCacheNexusPixels() method is:
2683 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2684 % NexusInfo *nexus_info)
2686 % A description of each parameter follows:
2688 % o cache: the pixel cache.
2690 % o nexus_info: the cache nexus to return the pixels.
2693 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2694 NexusInfo *nexus_info)
2699 assert(cache != NULL);
2700 cache_info=(CacheInfo *) cache;
2701 assert(cache_info->signature == MagickSignature);
2702 if (cache_info->storage_class == UndefinedClass)
2703 return((Quantum *) NULL);
2704 return(nexus_info->pixels);
2708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2712 + G e t P i x e l C a c h e P i x e l s %
2716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2718 % GetPixelCachePixels() returns the pixels associated with the specified image.
2720 % The format of the GetPixelCachePixels() method is:
2722 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2723 % ExceptionInfo *exception)
2725 % A description of each parameter follows:
2727 % o image: the image.
2729 % o length: the pixel cache length.
2731 % o exception: return any errors or warnings in this structure.
2734 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2735 ExceptionInfo *exception)
2740 assert(image != (const Image *) NULL);
2741 assert(image->signature == MagickSignature);
2742 assert(image->cache != (Cache) NULL);
2743 assert(length != (MagickSizeType *) NULL);
2744 assert(exception != (ExceptionInfo *) NULL);
2745 assert(exception->signature == MagickSignature);
2746 cache_info=(CacheInfo *) image->cache;
2747 assert(cache_info->signature == MagickSignature);
2749 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2750 return((void *) NULL);
2751 *length=cache_info->length;
2752 return((void *) cache_info->pixels);
2756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2760 + 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 %
2764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2766 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2768 % The format of the GetPixelCacheStorageClass() method is:
2770 % ClassType GetPixelCacheStorageClass(Cache cache)
2772 % A description of each parameter follows:
2774 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2776 % o cache: the pixel cache.
2779 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2784 assert(cache != (Cache) NULL);
2785 cache_info=(CacheInfo *) cache;
2786 assert(cache_info->signature == MagickSignature);
2787 if (cache_info->debug != MagickFalse)
2788 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2789 cache_info->filename);
2790 return(cache_info->storage_class);
2794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2798 + G e t P i x e l C a c h e T i l e S i z e %
2802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804 % GetPixelCacheTileSize() returns the pixel cache tile size.
2806 % The format of the GetPixelCacheTileSize() method is:
2808 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2811 % A description of each parameter follows:
2813 % o image: the image.
2815 % o width: the optimize cache tile width in pixels.
2817 % o height: the optimize cache tile height in pixels.
2820 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2826 assert(image != (Image *) NULL);
2827 assert(image->signature == MagickSignature);
2828 if (image->debug != MagickFalse)
2829 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2830 cache_info=(CacheInfo *) image->cache;
2831 assert(cache_info->signature == MagickSignature);
2832 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2833 if (GetImagePixelCacheType(image) == DiskCache)
2834 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2843 + 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 %
2847 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2849 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2850 % pixel cache. A virtual pixel is any pixel access that is outside the
2851 % boundaries of the image cache.
2853 % The format of the GetPixelCacheVirtualMethod() method is:
2855 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2857 % A description of each parameter follows:
2859 % o image: the image.
2862 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2867 assert(image != (Image *) NULL);
2868 assert(image->signature == MagickSignature);
2869 assert(image->cache != (Cache) NULL);
2870 cache_info=(CacheInfo *) image->cache;
2871 assert(cache_info->signature == MagickSignature);
2872 return(cache_info->virtual_pixel_method);
2876 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2880 + 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 %
2884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2886 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2887 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2889 % The format of the GetVirtualMetacontentFromCache() method is:
2891 % void *GetVirtualMetacontentFromCache(const Image *image)
2893 % A description of each parameter follows:
2895 % o image: the image.
2898 static const void *GetVirtualMetacontentFromCache(const Image *image)
2904 id = GetOpenMPThreadId();
2909 assert(image != (const Image *) NULL);
2910 assert(image->signature == MagickSignature);
2911 assert(image->cache != (Cache) NULL);
2912 cache_info=(CacheInfo *) image->cache;
2913 assert(cache_info->signature == MagickSignature);
2914 assert(id < (int) cache_info->number_threads);
2915 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2916 cache_info->nexus_info[id]);
2917 return(metacontent);
2921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2925 + 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 %
2929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2931 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2934 % The format of the GetVirtualMetacontentFromNexus() method is:
2936 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2937 % NexusInfo *nexus_info)
2939 % A description of each parameter follows:
2941 % o cache: the pixel cache.
2943 % o nexus_info: the cache nexus to return the meta-content.
2946 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2947 NexusInfo *nexus_info)
2952 assert(cache != (Cache) NULL);
2953 cache_info=(CacheInfo *) cache;
2954 assert(cache_info->signature == MagickSignature);
2955 if (cache_info->storage_class == UndefinedClass)
2956 return((void *) NULL);
2957 return(nexus_info->metacontent);
2961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2965 % G e t V i r t u a l M e t a c o n t e n t %
2969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2971 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2972 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2973 % returned if the meta-content are not available.
2975 % The format of the GetVirtualMetacontent() method is:
2977 % const void *GetVirtualMetacontent(const Image *image)
2979 % A description of each parameter follows:
2981 % o image: the image.
2984 MagickExport const void *GetVirtualMetacontent(const Image *image)
2990 id = GetOpenMPThreadId();
2995 assert(image != (const Image *) NULL);
2996 assert(image->signature == MagickSignature);
2997 assert(image->cache != (Cache) NULL);
2998 cache_info=(CacheInfo *) image->cache;
2999 assert(cache_info->signature == MagickSignature);
3000 metacontent=cache_info->methods.get_virtual_metacontent_from_handler(image);
3001 if (metacontent != (void *) NULL)
3002 return(metacontent);
3003 assert(id < (int) cache_info->number_threads);
3004 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3005 cache_info->nexus_info[id]);
3006 return(metacontent);
3010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3014 + 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 %
3018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3020 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3021 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3022 % is returned if the pixels are transferred, otherwise a NULL is returned.
3024 % The format of the GetVirtualPixelsFromNexus() method is:
3026 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
3027 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3028 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
3029 % ExceptionInfo *exception)
3031 % A description of each parameter follows:
3033 % o image: the image.
3035 % o virtual_pixel_method: the virtual pixel method.
3037 % o x,y,columns,rows: These values define the perimeter of a region of
3040 % o nexus_info: the cache nexus to acquire.
3042 % o exception: return any errors or warnings in this structure.
3049 0, 48, 12, 60, 3, 51, 15, 63,
3050 32, 16, 44, 28, 35, 19, 47, 31,
3051 8, 56, 4, 52, 11, 59, 7, 55,
3052 40, 24, 36, 20, 43, 27, 39, 23,
3053 2, 50, 14, 62, 1, 49, 13, 61,
3054 34, 18, 46, 30, 33, 17, 45, 29,
3055 10, 58, 6, 54, 9, 57, 5, 53,
3056 42, 26, 38, 22, 41, 25, 37, 21
3059 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3064 index=x+DitherMatrix[x & 0x07]-32L;
3067 if (index >= (ssize_t) columns)
3068 return((ssize_t) columns-1L);
3072 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3077 index=y+DitherMatrix[y & 0x07]-32L;
3080 if (index >= (ssize_t) rows)
3081 return((ssize_t) rows-1L);
3085 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3089 if (x >= (ssize_t) columns)
3090 return((ssize_t) (columns-1));
3094 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3098 if (y >= (ssize_t) rows)
3099 return((ssize_t) (rows-1));
3103 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3105 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3108 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3110 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3113 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3114 const size_t extent)
3120 Compute the remainder of dividing offset by extent. It returns not only
3121 the quotient (tile the offset falls in) but also the positive remainer
3122 within that tile such that 0 <= remainder < extent. This method is
3123 essentially a ldiv() using a floored modulo division rather than the
3124 normal default truncated modulo division.
3126 modulo.quotient=offset/(ssize_t) extent;
3129 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3133 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3134 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3135 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3136 ExceptionInfo *exception)
3153 virtual_pixel[CompositePixelChannel];
3158 register const Quantum
3171 register unsigned char
3178 *virtual_metacontent;
3183 assert(image != (const Image *) NULL);
3184 assert(image->signature == MagickSignature);
3185 assert(image->cache != (Cache) NULL);
3186 cache_info=(CacheInfo *) image->cache;
3187 assert(cache_info->signature == MagickSignature);
3188 if (cache_info->type == UndefinedCache)
3189 return((const Quantum *) NULL);
3192 region.width=columns;
3194 pixels=SetPixelCacheNexusPixels(image,ReadMode,®ion,nexus_info,exception);
3195 if (pixels == (Quantum *) NULL)
3196 return((const Quantum *) NULL);
3198 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3199 nexus_info->region.x;
3200 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3201 nexus_info->region.width-1L;
3202 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3203 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3204 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3205 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3211 Pixel request is inside cache extents.
3213 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3215 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3216 if (status == MagickFalse)
3217 return((const Quantum *) NULL);
3218 if (cache_info->metacontent_extent != 0)
3220 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3221 if (status == MagickFalse)
3222 return((const Quantum *) NULL);
3227 Pixel request is outside cache extents.
3229 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3230 virtual_nexus=AcquirePixelCacheNexus(1);
3231 if (virtual_nexus == (NexusInfo **) NULL)
3233 if (virtual_nexus != (NexusInfo **) NULL)
3234 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3235 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3236 "UnableToGetCacheNexus","`%s'",image->filename);
3237 return((const Quantum *) NULL);
3239 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3240 sizeof(*virtual_pixel));
3241 virtual_metacontent=(void *) NULL;
3242 switch (virtual_pixel_method)
3244 case BackgroundVirtualPixelMethod:
3245 case BlackVirtualPixelMethod:
3246 case GrayVirtualPixelMethod:
3247 case TransparentVirtualPixelMethod:
3248 case MaskVirtualPixelMethod:
3249 case WhiteVirtualPixelMethod:
3250 case EdgeVirtualPixelMethod:
3251 case CheckerTileVirtualPixelMethod:
3252 case HorizontalTileVirtualPixelMethod:
3253 case VerticalTileVirtualPixelMethod:
3255 if (cache_info->metacontent_extent != 0)
3258 Acquire a metacontent buffer.
3260 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3261 cache_info->metacontent_extent);
3262 if (virtual_metacontent == (void *) NULL)
3264 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3265 (void) ThrowMagickException(exception,GetMagickModule(),
3266 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3267 return((const Quantum *) NULL);
3269 (void) ResetMagickMemory(virtual_metacontent,0,
3270 cache_info->metacontent_extent);
3272 switch (virtual_pixel_method)
3274 case BlackVirtualPixelMethod:
3276 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3277 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3278 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3281 case GrayVirtualPixelMethod:
3283 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3284 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3286 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3289 case TransparentVirtualPixelMethod:
3291 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3292 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3293 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3296 case MaskVirtualPixelMethod:
3297 case WhiteVirtualPixelMethod:
3299 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3300 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3301 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3306 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3308 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3310 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3312 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3314 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3324 for (v=0; v < (ssize_t) rows; v++)
3326 for (u=0; u < (ssize_t) columns; u+=length)
3328 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3329 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3330 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3338 Transfer a single pixel.
3340 length=(MagickSizeType) 1;
3341 switch (virtual_pixel_method)
3345 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3346 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3347 1UL,1UL,*virtual_nexus,exception);
3348 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3351 case RandomVirtualPixelMethod:
3353 if (cache_info->random_info == (RandomInfo *) NULL)
3354 cache_info->random_info=AcquireRandomInfo();
3355 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3356 RandomX(cache_info->random_info,cache_info->columns),
3357 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3358 *virtual_nexus,exception);
3359 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3362 case DitherVirtualPixelMethod:
3364 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3365 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3366 1UL,1UL,*virtual_nexus,exception);
3367 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3370 case TileVirtualPixelMethod:
3372 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3373 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3374 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3375 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3377 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3380 case MirrorVirtualPixelMethod:
3382 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3383 if ((x_modulo.quotient & 0x01) == 1L)
3384 x_modulo.remainder=(ssize_t) cache_info->columns-
3385 x_modulo.remainder-1L;
3386 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3387 if ((y_modulo.quotient & 0x01) == 1L)
3388 y_modulo.remainder=(ssize_t) cache_info->rows-
3389 y_modulo.remainder-1L;
3390 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3391 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3393 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3396 case HorizontalTileEdgeVirtualPixelMethod:
3398 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3399 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3400 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3401 *virtual_nexus,exception);
3402 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3405 case VerticalTileEdgeVirtualPixelMethod:
3407 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3408 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3409 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3410 *virtual_nexus,exception);
3411 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3414 case BackgroundVirtualPixelMethod:
3415 case BlackVirtualPixelMethod:
3416 case GrayVirtualPixelMethod:
3417 case TransparentVirtualPixelMethod:
3418 case MaskVirtualPixelMethod:
3419 case WhiteVirtualPixelMethod:
3422 r=virtual_metacontent;
3425 case EdgeVirtualPixelMethod:
3426 case CheckerTileVirtualPixelMethod:
3428 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3429 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3430 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3433 r=virtual_metacontent;
3436 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3437 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3439 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3442 case HorizontalTileVirtualPixelMethod:
3444 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3447 r=virtual_metacontent;
3450 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3451 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3452 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3453 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3455 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3458 case VerticalTileVirtualPixelMethod:
3460 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3463 r=virtual_metacontent;
3466 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3467 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3468 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3469 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3471 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3475 if (p == (const Quantum *) NULL)
3477 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3479 q+=cache_info->number_channels;
3480 if ((s != (void *) NULL) && (r != (const void *) NULL))
3482 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3483 s+=cache_info->metacontent_extent;
3488 Transfer a run of pixels.
3490 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3491 length,1UL,*virtual_nexus,exception);
3492 if (p == (const Quantum *) NULL)
3494 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3495 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3496 q+=length*cache_info->number_channels;
3497 if ((r != (void *) NULL) && (s != (const void *) NULL))
3499 (void) memcpy(s,r,(size_t) length);
3500 s+=length*cache_info->metacontent_extent;
3507 if (virtual_metacontent != (void *) NULL)
3508 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3509 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3518 + G e t V i r t u a l P i x e l C a c h e %
3522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3524 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3525 % cache as defined by the geometry parameters. A pointer to the pixels
3526 % is returned if the pixels are transferred, otherwise a NULL is returned.
3528 % The format of the GetVirtualPixelCache() method is:
3530 % const Quantum *GetVirtualPixelCache(const Image *image,
3531 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3532 % const ssize_t y,const size_t columns,const size_t rows,
3533 % ExceptionInfo *exception)
3535 % A description of each parameter follows:
3537 % o image: the image.
3539 % o virtual_pixel_method: the virtual pixel method.
3541 % o x,y,columns,rows: These values define the perimeter of a region of
3544 % o exception: return any errors or warnings in this structure.
3547 static const Quantum *GetVirtualPixelCache(const Image *image,
3548 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3549 const size_t columns,const size_t rows,ExceptionInfo *exception)
3555 id = GetOpenMPThreadId();
3560 assert(image != (const Image *) NULL);
3561 assert(image->signature == MagickSignature);
3562 assert(image->cache != (Cache) NULL);
3563 cache_info=(CacheInfo *) image->cache;
3564 assert(cache_info->signature == MagickSignature);
3565 assert(id < (int) cache_info->number_threads);
3566 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3567 cache_info->nexus_info[id],exception);
3572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3576 % G e t V i r t u a l P i x e l Q u e u e %
3580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3582 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3583 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3585 % The format of the GetVirtualPixelQueue() method is:
3587 % const Quantum *GetVirtualPixelQueue(const Image image)
3589 % A description of each parameter follows:
3591 % o image: the image.
3594 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3600 id = GetOpenMPThreadId();
3602 assert(image != (const Image *) NULL);
3603 assert(image->signature == MagickSignature);
3604 assert(image->cache != (Cache) NULL);
3605 cache_info=(CacheInfo *) image->cache;
3606 assert(cache_info->signature == MagickSignature);
3607 if (cache_info->methods.get_virtual_pixels_handler !=
3608 (GetVirtualPixelsHandler) NULL)
3609 return(cache_info->methods.get_virtual_pixels_handler(image));
3610 assert(id < (int) cache_info->number_threads);
3611 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3619 % G e t V i r t u a l P i x e l s %
3623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3625 % GetVirtualPixels() returns an immutable pixel region. If the
3626 % region is successfully accessed, a pointer to it is returned, otherwise
3627 % NULL is returned. The returned pointer may point to a temporary working
3628 % copy of the pixels or it may point to the original pixels in memory.
3629 % Performance is maximized if the selected region is part of one row, or one
3630 % or more full rows, since there is opportunity to access the pixels in-place
3631 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3632 % returned pointer must *never* be deallocated by the user.
3634 % Pixels accessed via the returned pointer represent a simple array of type
3635 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3636 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3637 % access the meta-content (of type void) corresponding to the the
3640 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3642 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3643 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3644 % GetCacheViewAuthenticPixels() instead.
3646 % The format of the GetVirtualPixels() method is:
3648 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3649 % const ssize_t y,const size_t columns,const size_t rows,
3650 % ExceptionInfo *exception)
3652 % A description of each parameter follows:
3654 % o image: the image.
3656 % o x,y,columns,rows: These values define the perimeter of a region of
3659 % o exception: return any errors or warnings in this structure.
3662 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3663 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3664 ExceptionInfo *exception)
3670 id = GetOpenMPThreadId();
3675 assert(image != (const Image *) NULL);
3676 assert(image->signature == MagickSignature);
3677 assert(image->cache != (Cache) NULL);
3678 cache_info=(CacheInfo *) image->cache;
3679 assert(cache_info->signature == MagickSignature);
3680 if (cache_info->methods.get_virtual_pixel_handler !=
3681 (GetVirtualPixelHandler) NULL)
3682 return(cache_info->methods.get_virtual_pixel_handler(image,
3683 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3684 assert(id < (int) cache_info->number_threads);
3685 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3686 columns,rows,cache_info->nexus_info[id],exception);
3691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3695 + 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 %
3699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3701 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3702 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3704 % The format of the GetVirtualPixelsCache() method is:
3706 % Quantum *GetVirtualPixelsCache(const Image *image)
3708 % A description of each parameter follows:
3710 % o image: the image.
3713 static const Quantum *GetVirtualPixelsCache(const Image *image)
3719 id = GetOpenMPThreadId();
3721 assert(image != (const Image *) NULL);
3722 assert(image->signature == MagickSignature);
3723 assert(image->cache != (Cache) NULL);
3724 cache_info=(CacheInfo *) image->cache;
3725 assert(cache_info->signature == MagickSignature);
3726 assert(id < (int) cache_info->number_threads);
3727 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3735 + G e t V i r t u a l P i x e l s N e x u s %
3739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3741 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3744 % The format of the GetVirtualPixelsNexus() method is:
3746 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3747 % NexusInfo *nexus_info)
3749 % A description of each parameter follows:
3751 % o cache: the pixel cache.
3753 % o nexus_info: the cache nexus to return the colormap pixels.
3756 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3757 NexusInfo *nexus_info)
3762 assert(cache != (Cache) NULL);
3763 cache_info=(CacheInfo *) cache;
3764 assert(cache_info->signature == MagickSignature);
3765 if (cache_info->storage_class == UndefinedClass)
3766 return((Quantum *) NULL);
3767 return((const Quantum *) nexus_info->pixels);
3771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3775 + O p e n P i x e l C a c h e %
3779 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3781 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3782 % dimensions, allocating space for the image pixels and optionally the
3783 % metacontent, and memory mapping the cache if it is disk based. The cache
3784 % nexus array is initialized as well.
3786 % The format of the OpenPixelCache() method is:
3788 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3789 % ExceptionInfo *exception)
3791 % A description of each parameter follows:
3793 % o image: the image.
3795 % o mode: ReadMode, WriteMode, or IOMode.
3797 % o exception: return any errors or warnings in this structure.
3801 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3803 cache_info->mapped=MagickFalse;
3804 cache_info->pixels=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
3805 (size_t) cache_info->length));
3806 if (cache_info->pixels == (Quantum *) NULL)
3808 cache_info->mapped=MagickTrue;
3809 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3810 cache_info->length);
3814 static MagickBooleanType SetPixelCacheExtent(Image *image,MagickSizeType length)
3824 cache_info=(CacheInfo *) image->cache;
3825 if (image->debug != MagickFalse)
3828 format[MaxTextExtent],
3829 message[MaxTextExtent];
3831 (void) FormatMagickSize(length,MagickFalse,format);
3832 (void) FormatLocaleString(message,MaxTextExtent,
3833 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3834 cache_info->cache_filename,cache_info->file,format);
3835 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3837 if (length != (MagickSizeType) ((MagickOffsetType) length))
3838 return(MagickFalse);
3839 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3841 return(MagickFalse);
3842 if ((MagickSizeType) offset >= length)
3844 extent=(MagickOffsetType) length-1;
3845 count=WritePixelCacheRegion(cache_info,extent,1,(const unsigned char *) "");
3846 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3847 if (cache_info->synchronize != MagickFalse)
3852 status=posix_fallocate(cache_info->file,offset+1,extent-offset);
3854 return(MagickFalse);
3857 return(count != (MagickOffsetType) 1 ? MagickFalse : MagickTrue);
3860 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3861 ExceptionInfo *exception)
3868 format[MaxTextExtent],
3869 message[MaxTextExtent];
3882 assert(image != (const Image *) NULL);
3883 assert(image->signature == MagickSignature);
3884 assert(image->cache != (Cache) NULL);
3885 if (image->debug != MagickFalse)
3886 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3887 if ((image->columns == 0) || (image->rows == 0))
3888 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3889 cache_info=(CacheInfo *) image->cache;
3890 assert(cache_info->signature == MagickSignature);
3891 source_info=(*cache_info);
3892 source_info.file=(-1);
3893 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3894 image->filename,(double) GetImageIndexInList(image));
3895 cache_info->storage_class=image->storage_class;
3896 cache_info->colorspace=image->colorspace;
3897 cache_info->alpha_trait=image->alpha_trait;
3898 cache_info->mask=image->mask;
3899 cache_info->rows=image->rows;
3900 cache_info->columns=image->columns;
3901 InitializePixelChannelMap(image);
3902 cache_info->number_channels=GetPixelChannels(image);
3903 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
3904 sizeof(*image->channel_map));
3905 cache_info->metacontent_extent=image->metacontent_extent;
3906 cache_info->mode=mode;
3907 if (image->ping != MagickFalse)
3909 cache_info->type=PingCache;
3910 cache_info->pixels=(Quantum *) NULL;
3911 cache_info->metacontent=(void *) NULL;
3912 cache_info->length=0;
3915 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3916 packet_size=cache_info->number_channels*sizeof(Quantum);
3917 if (image->metacontent_extent != 0)
3918 packet_size+=cache_info->metacontent_extent;
3919 length=number_pixels*packet_size;
3920 columns=(size_t) (length/cache_info->rows/packet_size);
3921 if (cache_info->columns != columns)
3922 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3924 cache_info->length=length;
3925 status=AcquireMagickResource(AreaResource,cache_info->length);
3926 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
3927 cache_info->metacontent_extent);
3928 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3930 status=AcquireMagickResource(MemoryResource,cache_info->length);
3931 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3932 (cache_info->type == MemoryCache))
3934 AllocatePixelCachePixels(cache_info);
3935 if (cache_info->pixels == (Quantum *) NULL)
3936 cache_info->pixels=source_info.pixels;
3940 Create memory pixel cache.
3943 cache_info->type=MemoryCache;
3944 cache_info->metacontent=(void *) NULL;
3945 if (cache_info->metacontent_extent != 0)
3946 cache_info->metacontent=(void *) (cache_info->pixels+
3947 number_pixels*cache_info->number_channels);
3948 if ((source_info.storage_class != UndefinedClass) &&
3951 status=ClonePixelCachePixels(cache_info,&source_info,
3953 RelinquishPixelCachePixels(&source_info);
3955 if (image->debug != MagickFalse)
3957 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
3958 (void) FormatLocaleString(message,MaxTextExtent,
3959 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
3960 cache_info->filename,cache_info->mapped != MagickFalse ?
3961 "anonymous" : "heap",(double) cache_info->columns,(double)
3962 cache_info->rows,(double) cache_info->number_channels,
3964 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3970 RelinquishMagickResource(MemoryResource,cache_info->length);
3973 Create pixel cache on disk.
3975 status=AcquireMagickResource(DiskResource,cache_info->length);
3976 if (status == MagickFalse)
3981 hosts=GetImageRegistry(StringRegistryType,"cache-hosts",exception);
3982 if (hosts != (const char *) NULL)
3983 abort(); /* create distributed cache */
3984 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3985 "CacheResourcesExhausted","`%s'",image->filename);
3986 return(MagickFalse);
3988 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
3990 (void) ClosePixelCacheOnDisk(cache_info);
3991 *cache_info->cache_filename='\0';
3993 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
3995 RelinquishMagickResource(DiskResource,cache_info->length);
3996 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
3998 return(MagickFalse);
4000 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
4001 cache_info->length);
4002 if (status == MagickFalse)
4004 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4006 return(MagickFalse);
4008 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4009 cache_info->metacontent_extent);
4010 if (length != (MagickSizeType) ((size_t) length))
4011 cache_info->type=DiskCache;
4014 status=AcquireMagickResource(MapResource,cache_info->length);
4015 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4016 (cache_info->type != MemoryCache))
4017 cache_info->type=DiskCache;
4020 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4021 cache_info->offset,(size_t) cache_info->length);
4022 if (cache_info->pixels == (Quantum *) NULL)
4024 cache_info->type=DiskCache;
4025 cache_info->pixels=source_info.pixels;
4030 Create file-backed memory-mapped pixel cache.
4033 (void) ClosePixelCacheOnDisk(cache_info);
4034 cache_info->type=MapCache;
4035 cache_info->mapped=MagickTrue;
4036 cache_info->metacontent=(void *) NULL;
4037 if (cache_info->metacontent_extent != 0)
4038 cache_info->metacontent=(void *) (cache_info->pixels+
4039 number_pixels*cache_info->number_channels);
4040 if ((source_info.storage_class != UndefinedClass) &&
4043 status=ClonePixelCachePixels(cache_info,&source_info,
4045 RelinquishPixelCachePixels(&source_info);
4047 if (image->debug != MagickFalse)
4049 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
4050 (void) FormatLocaleString(message,MaxTextExtent,
4051 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4052 cache_info->filename,cache_info->cache_filename,
4053 cache_info->file,(double) cache_info->columns,(double)
4054 cache_info->rows,(double) cache_info->number_channels,
4056 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4062 RelinquishMagickResource(MapResource,cache_info->length);
4065 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4067 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4068 RelinquishPixelCachePixels(&source_info);
4070 if (image->debug != MagickFalse)
4072 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4073 (void) FormatLocaleString(message,MaxTextExtent,
4074 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4075 cache_info->cache_filename,cache_info->file,(double)
4076 cache_info->columns,(double) cache_info->rows,(double)
4077 cache_info->number_channels,format);
4078 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4088 + P e r s i s t P i x e l C a c h e %
4092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4094 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4095 % persistent pixel cache is one that resides on disk and is not destroyed
4096 % when the program exits.
4098 % The format of the PersistPixelCache() method is:
4100 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4101 % const MagickBooleanType attach,MagickOffsetType *offset,
4102 % ExceptionInfo *exception)
4104 % A description of each parameter follows:
4106 % o image: the image.
4108 % o filename: the persistent pixel cache filename.
4110 % o attach: A value other than zero initializes the persistent pixel cache.
4112 % o initialize: A value other than zero initializes the persistent pixel
4115 % o offset: the offset in the persistent cache to store pixels.
4117 % o exception: return any errors or warnings in this structure.
4120 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4121 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4122 ExceptionInfo *exception)
4137 assert(image != (Image *) NULL);
4138 assert(image->signature == MagickSignature);
4139 if (image->debug != MagickFalse)
4140 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4141 assert(image->cache != (void *) NULL);
4142 assert(filename != (const char *) NULL);
4143 assert(offset != (MagickOffsetType *) NULL);
4144 page_size=GetMagickPageSize();
4145 cache_info=(CacheInfo *) image->cache;
4146 assert(cache_info->signature == MagickSignature);
4147 if (attach != MagickFalse)
4150 Attach existing persistent pixel cache.
4152 if (image->debug != MagickFalse)
4153 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4154 "attach persistent cache");
4155 (void) CopyMagickString(cache_info->cache_filename,filename,
4157 cache_info->type=DiskCache;
4158 cache_info->offset=(*offset);
4159 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4160 return(MagickFalse);
4161 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4164 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4165 (cache_info->reference_count == 1))
4167 LockSemaphoreInfo(cache_info->semaphore);
4168 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4169 (cache_info->reference_count == 1))
4175 Usurp existing persistent pixel cache.
4177 status=rename_utf8(cache_info->cache_filename,filename);
4180 (void) CopyMagickString(cache_info->cache_filename,filename,
4182 *offset+=cache_info->length+page_size-(cache_info->length %
4184 UnlockSemaphoreInfo(cache_info->semaphore);
4185 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4186 if (image->debug != MagickFalse)
4187 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4188 "Usurp resident persistent cache");
4192 UnlockSemaphoreInfo(cache_info->semaphore);
4195 Clone persistent pixel cache.
4197 clone_image=(*image);
4198 clone_info=(CacheInfo *) clone_image.cache;
4199 image->cache=ClonePixelCache(cache_info);
4200 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4201 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4202 cache_info->type=DiskCache;
4203 cache_info->offset=(*offset);
4204 cache_info=(CacheInfo *) image->cache;
4205 status=OpenPixelCache(image,IOMode,exception);
4206 if (status != MagickFalse)
4207 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4208 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4209 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4218 + 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 %
4222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4224 % QueueAuthenticPixelCacheNexus() allocates an region to store image pixels as
4225 % defined by the region rectangle and returns a pointer to the region. This
4226 % region is subsequently transferred from the pixel cache with
4227 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4228 % pixels are transferred, otherwise a NULL is returned.
4230 % The format of the QueueAuthenticPixelCacheNexus() method is:
4232 % Quantum *QueueAuthenticPixelCacheNexus(Image *image,const ssize_t x,
4233 % const ssize_t y,const size_t columns,const size_t rows,
4234 % const MagickBooleanType clone,NexusInfo *nexus_info,
4235 % ExceptionInfo *exception)
4237 % A description of each parameter follows:
4239 % o image: the image.
4241 % o x,y,columns,rows: These values define the perimeter of a region of
4244 % o nexus_info: the cache nexus to set.
4246 % o clone: clone the pixel cache.
4248 % o exception: return any errors or warnings in this structure.
4251 MagickPrivate Quantum *QueueAuthenticPixelCacheNexus(Image *image,
4252 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
4253 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4268 Validate pixel cache geometry.
4270 assert(image != (const Image *) NULL);
4271 assert(image->signature == MagickSignature);
4272 assert(image->cache != (Cache) NULL);
4273 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4274 if (cache_info == (Cache) NULL)
4275 return((Quantum *) NULL);
4276 assert(cache_info->signature == MagickSignature);
4277 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4279 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4280 "NoPixelsDefinedInCache","`%s'",image->filename);
4281 return((Quantum *) NULL);
4283 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4284 (y >= (ssize_t) cache_info->rows))
4286 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4287 "PixelsAreNotAuthentic","`%s'",image->filename);
4288 return((Quantum *) NULL);
4290 offset=(MagickOffsetType) y*cache_info->columns+x;
4292 return((Quantum *) NULL);
4293 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4294 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4295 if ((MagickSizeType) offset >= number_pixels)
4296 return((Quantum *) NULL);
4302 region.width=columns;
4304 return(SetPixelCacheNexusPixels(image,WriteMode,®ion,nexus_info,exception));
4308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4312 + 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 %
4316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4318 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4319 % defined by the region rectangle and returns a pointer to the region. This
4320 % region is subsequently transferred from the pixel cache with
4321 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4322 % pixels are transferred, otherwise a NULL is returned.
4324 % The format of the QueueAuthenticPixelsCache() method is:
4326 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4327 % const ssize_t y,const size_t columns,const size_t rows,
4328 % ExceptionInfo *exception)
4330 % A description of each parameter follows:
4332 % o image: the image.
4334 % o x,y,columns,rows: These values define the perimeter of a region of
4337 % o exception: return any errors or warnings in this structure.
4340 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4341 const ssize_t y,const size_t columns,const size_t rows,
4342 ExceptionInfo *exception)
4348 id = GetOpenMPThreadId();
4353 assert(image != (const Image *) NULL);
4354 assert(image->signature == MagickSignature);
4355 assert(image->cache != (Cache) NULL);
4356 cache_info=(CacheInfo *) image->cache;
4357 assert(cache_info->signature == MagickSignature);
4358 assert(id < (int) cache_info->number_threads);
4359 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4360 cache_info->nexus_info[id],exception);
4365 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4369 % Q u e u e A u t h e n t i c P i x e l s %
4373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4375 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4376 % successfully initialized a pointer to a Quantum array representing the
4377 % region is returned, otherwise NULL is returned. The returned pointer may
4378 % point to a temporary working buffer for the pixels or it may point to the
4379 % final location of the pixels in memory.
4381 % Write-only access means that any existing pixel values corresponding to
4382 % the region are ignored. This is useful if the initial image is being
4383 % created from scratch, or if the existing pixel values are to be
4384 % completely replaced without need to refer to their pre-existing values.
4385 % The application is free to read and write the pixel buffer returned by
4386 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4387 % initialize the pixel array values. Initializing pixel array values is the
4388 % application's responsibility.
4390 % Performance is maximized if the selected region is part of one row, or
4391 % one or more full rows, since then there is opportunity to access the
4392 % pixels in-place (without a copy) if the image is in memory, or in a
4393 % memory-mapped file. The returned pointer must *never* be deallocated
4396 % Pixels accessed via the returned pointer represent a simple array of type
4397 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4398 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4399 % obtain the meta-content (of type void) corresponding to the region.
4400 % Once the Quantum (and/or Quantum) array has been updated, the
4401 % changes must be saved back to the underlying image using
4402 % SyncAuthenticPixels() or they may be lost.
4404 % The format of the QueueAuthenticPixels() method is:
4406 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4407 % const ssize_t y,const size_t columns,const size_t rows,
4408 % ExceptionInfo *exception)
4410 % A description of each parameter follows:
4412 % o image: the image.
4414 % o x,y,columns,rows: These values define the perimeter of a region of
4417 % o exception: return any errors or warnings in this structure.
4420 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4421 const ssize_t y,const size_t columns,const size_t rows,
4422 ExceptionInfo *exception)
4428 id = GetOpenMPThreadId();
4433 assert(image != (Image *) NULL);
4434 assert(image->signature == MagickSignature);
4435 assert(image->cache != (Cache) NULL);
4436 cache_info=(CacheInfo *) image->cache;
4437 assert(cache_info->signature == MagickSignature);
4438 if (cache_info->methods.queue_authentic_pixels_handler !=
4439 (QueueAuthenticPixelsHandler) NULL)
4441 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4445 assert(id < (int) cache_info->number_threads);
4446 q=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4447 cache_info->nexus_info[id],exception);
4452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4456 + 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 %
4460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4462 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4465 % The format of the ReadPixelCacheMetacontent() method is:
4467 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4468 % NexusInfo *nexus_info,ExceptionInfo *exception)
4470 % A description of each parameter follows:
4472 % o cache_info: the pixel cache.
4474 % o nexus_info: the cache nexus to read the metacontent.
4476 % o exception: return any errors or warnings in this structure.
4479 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4480 NexusInfo *nexus_info,ExceptionInfo *exception)
4493 register unsigned char
4499 if (cache_info->metacontent_extent == 0)
4500 return(MagickFalse);
4501 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4503 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4504 nexus_info->region.x;
4505 length=(MagickSizeType) nexus_info->region.width*
4506 cache_info->metacontent_extent;
4507 rows=nexus_info->region.height;
4509 q=(unsigned char *) nexus_info->metacontent;
4510 switch (cache_info->type)
4515 register unsigned char
4519 Read meta-content from memory.
4521 if ((cache_info->columns == nexus_info->region.width) &&
4522 (extent == (MagickSizeType) ((size_t) extent)))
4527 p=(unsigned char *) cache_info->metacontent+offset*
4528 cache_info->metacontent_extent;
4529 for (y=0; y < (ssize_t) rows; y++)
4531 (void) memcpy(q,p,(size_t) length);
4532 p+=cache_info->metacontent_extent*cache_info->columns;
4533 q+=cache_info->metacontent_extent*nexus_info->region.width;
4540 Read meta content from disk.
4542 LockSemaphoreInfo(cache_info->file_semaphore);
4543 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4545 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4546 cache_info->cache_filename);
4547 UnlockSemaphoreInfo(cache_info->file_semaphore);
4548 return(MagickFalse);
4550 if ((cache_info->columns == nexus_info->region.width) &&
4551 (extent <= MagickMaxBufferExtent))
4556 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4557 for (y=0; y < (ssize_t) rows; y++)
4559 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4560 cache_info->number_channels*sizeof(Quantum)+offset*
4561 cache_info->metacontent_extent,length,(unsigned char *) q);
4562 if ((MagickSizeType) count != length)
4564 offset+=cache_info->columns;
4565 q+=cache_info->metacontent_extent*nexus_info->region.width;
4567 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4568 (void) ClosePixelCacheOnDisk(cache_info);
4569 UnlockSemaphoreInfo(cache_info->file_semaphore);
4570 if (y < (ssize_t) rows)
4572 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4573 cache_info->cache_filename);
4574 return(MagickFalse);
4578 case DistributedCache:
4586 if ((cache_info->debug != MagickFalse) &&
4587 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4588 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4589 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4590 nexus_info->region.width,(double) nexus_info->region.height,(double)
4591 nexus_info->region.x,(double) nexus_info->region.y);
4596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4600 + R e a d P i x e l C a c h e P i x e l s %
4604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4606 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4609 % The format of the ReadPixelCachePixels() method is:
4611 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4612 % NexusInfo *nexus_info,ExceptionInfo *exception)
4614 % A description of each parameter follows:
4616 % o cache_info: the pixel cache.
4618 % o nexus_info: the cache nexus to read the pixels.
4620 % o exception: return any errors or warnings in this structure.
4623 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4624 NexusInfo *nexus_info,ExceptionInfo *exception)
4643 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4645 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4646 nexus_info->region.x;
4647 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4649 rows=nexus_info->region.height;
4651 q=nexus_info->pixels;
4652 switch (cache_info->type)
4661 Read pixels from memory.
4663 if ((cache_info->columns == nexus_info->region.width) &&
4664 (extent == (MagickSizeType) ((size_t) extent)))
4669 p=cache_info->pixels+offset*cache_info->number_channels;
4670 for (y=0; y < (ssize_t) rows; y++)
4672 (void) memcpy(q,p,(size_t) length);
4673 p+=cache_info->number_channels*cache_info->columns;
4674 q+=cache_info->number_channels*nexus_info->region.width;
4681 Read pixels from disk.
4683 LockSemaphoreInfo(cache_info->file_semaphore);
4684 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4686 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4687 cache_info->cache_filename);
4688 UnlockSemaphoreInfo(cache_info->file_semaphore);
4689 return(MagickFalse);
4691 if ((cache_info->columns == nexus_info->region.width) &&
4692 (extent <= MagickMaxBufferExtent))
4697 for (y=0; y < (ssize_t) rows; y++)
4699 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4700 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4701 if ((MagickSizeType) count != length)
4703 offset+=cache_info->columns;
4704 q+=cache_info->number_channels*nexus_info->region.width;
4706 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4707 (void) ClosePixelCacheOnDisk(cache_info);
4708 UnlockSemaphoreInfo(cache_info->file_semaphore);
4709 if (y < (ssize_t) rows)
4711 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4712 cache_info->cache_filename);
4713 return(MagickFalse);
4717 case DistributedCache:
4725 if ((cache_info->debug != MagickFalse) &&
4726 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4727 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4728 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4729 nexus_info->region.width,(double) nexus_info->region.height,(double)
4730 nexus_info->region.x,(double) nexus_info->region.y);
4735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4739 + R e f e r e n c e P i x e l C a c h e %
4743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4745 % ReferencePixelCache() increments the reference count associated with the
4746 % pixel cache returning a pointer to the cache.
4748 % The format of the ReferencePixelCache method is:
4750 % Cache ReferencePixelCache(Cache cache_info)
4752 % A description of each parameter follows:
4754 % o cache_info: the pixel cache.
4757 MagickPrivate Cache ReferencePixelCache(Cache cache)
4762 assert(cache != (Cache *) NULL);
4763 cache_info=(CacheInfo *) cache;
4764 assert(cache_info->signature == MagickSignature);
4765 LockSemaphoreInfo(cache_info->semaphore);
4766 cache_info->reference_count++;
4767 UnlockSemaphoreInfo(cache_info->semaphore);
4772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4776 + S e t P i x e l C a c h e M e t h o d s %
4780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4782 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4784 % The format of the SetPixelCacheMethods() method is:
4786 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4788 % A description of each parameter follows:
4790 % o cache: the pixel cache.
4792 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4795 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4800 GetOneAuthenticPixelFromHandler
4801 get_one_authentic_pixel_from_handler;
4803 GetOneVirtualPixelFromHandler
4804 get_one_virtual_pixel_from_handler;
4807 Set cache pixel methods.
4809 assert(cache != (Cache) NULL);
4810 assert(cache_methods != (CacheMethods *) NULL);
4811 cache_info=(CacheInfo *) cache;
4812 assert(cache_info->signature == MagickSignature);
4813 if (cache_info->debug != MagickFalse)
4814 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4815 cache_info->filename);
4816 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4817 cache_info->methods.get_virtual_pixel_handler=
4818 cache_methods->get_virtual_pixel_handler;
4819 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4820 cache_info->methods.destroy_pixel_handler=
4821 cache_methods->destroy_pixel_handler;
4822 if (cache_methods->get_virtual_metacontent_from_handler !=
4823 (GetVirtualMetacontentFromHandler) NULL)
4824 cache_info->methods.get_virtual_metacontent_from_handler=
4825 cache_methods->get_virtual_metacontent_from_handler;
4826 if (cache_methods->get_authentic_pixels_handler !=
4827 (GetAuthenticPixelsHandler) NULL)
4828 cache_info->methods.get_authentic_pixels_handler=
4829 cache_methods->get_authentic_pixels_handler;
4830 if (cache_methods->queue_authentic_pixels_handler !=
4831 (QueueAuthenticPixelsHandler) NULL)
4832 cache_info->methods.queue_authentic_pixels_handler=
4833 cache_methods->queue_authentic_pixels_handler;
4834 if (cache_methods->sync_authentic_pixels_handler !=
4835 (SyncAuthenticPixelsHandler) NULL)
4836 cache_info->methods.sync_authentic_pixels_handler=
4837 cache_methods->sync_authentic_pixels_handler;
4838 if (cache_methods->get_authentic_pixels_from_handler !=
4839 (GetAuthenticPixelsFromHandler) NULL)
4840 cache_info->methods.get_authentic_pixels_from_handler=
4841 cache_methods->get_authentic_pixels_from_handler;
4842 if (cache_methods->get_authentic_metacontent_from_handler !=
4843 (GetAuthenticMetacontentFromHandler) NULL)
4844 cache_info->methods.get_authentic_metacontent_from_handler=
4845 cache_methods->get_authentic_metacontent_from_handler;
4846 get_one_virtual_pixel_from_handler=
4847 cache_info->methods.get_one_virtual_pixel_from_handler;
4848 if (get_one_virtual_pixel_from_handler !=
4849 (GetOneVirtualPixelFromHandler) NULL)
4850 cache_info->methods.get_one_virtual_pixel_from_handler=
4851 cache_methods->get_one_virtual_pixel_from_handler;
4852 get_one_authentic_pixel_from_handler=
4853 cache_methods->get_one_authentic_pixel_from_handler;
4854 if (get_one_authentic_pixel_from_handler !=
4855 (GetOneAuthenticPixelFromHandler) NULL)
4856 cache_info->methods.get_one_authentic_pixel_from_handler=
4857 cache_methods->get_one_authentic_pixel_from_handler;
4861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4865 + S e t P i x e l C a c h e N e x u s P i x e l s %
4869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4871 % SetPixelCacheNexusPixels() defines the region of the cache for the
4872 % specified cache nexus.
4874 % The format of the SetPixelCacheNexusPixels() method is:
4876 % Quantum SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4877 % const RectangleInfo *region,NexusInfo *nexus_info,
4878 % ExceptionInfo *exception)
4880 % A description of each parameter follows:
4882 % o image: the image.
4884 % o mode: ReadMode, WriteMode, or IOMode.
4886 % o region: A pointer to the RectangleInfo structure that defines the
4887 % region of this particular cache nexus.
4889 % o nexus_info: the cache nexus to set.
4891 % o exception: return any errors or warnings in this structure.
4895 static inline MagickBooleanType AcquireCacheNexusPixels(
4896 const CacheInfo *restrict cache_info,NexusInfo *nexus_info,
4897 ExceptionInfo *exception)
4899 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4900 return(MagickFalse);
4901 nexus_info->mapped=MagickFalse;
4902 nexus_info->cache=(Quantum *) MagickAssumeAligned(AcquireAlignedMemory(1,
4903 (size_t) nexus_info->length));
4904 if (nexus_info->cache == (Quantum *) NULL)
4906 nexus_info->mapped=MagickTrue;
4907 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4908 nexus_info->length);
4910 if (nexus_info->cache == (Quantum *) NULL)
4912 (void) ThrowMagickException(exception,GetMagickModule(),
4913 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4914 cache_info->filename);
4915 return(MagickFalse);
4920 static inline void PrefetchPixelCacheNexusPixels(const NexusInfo *nexus_info,
4923 if (mode == ReadMode)
4925 MagickCachePrefetch((unsigned char *) nexus_info->pixels,0,1);
4928 MagickCachePrefetch((unsigned char *) nexus_info->pixels,1,1);
4931 static Quantum *SetPixelCacheNexusPixels(const Image *image,const MapMode mode,
4932 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4944 cache_info=(CacheInfo *) image->cache;
4945 assert(cache_info->signature == MagickSignature);
4946 if (cache_info->type == UndefinedCache)
4947 return((Quantum *) NULL);
4948 nexus_info->region=(*region);
4949 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache))
4955 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4956 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4957 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4958 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4959 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4960 ((nexus_info->region.width == cache_info->columns) ||
4961 ((nexus_info->region.width % cache_info->columns) == 0)))))
4967 Pixels are accessed directly from memory.
4969 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4970 nexus_info->region.x;
4971 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
4973 nexus_info->metacontent=(void *) NULL;
4974 if (cache_info->metacontent_extent != 0)
4975 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
4976 offset*cache_info->metacontent_extent;
4977 PrefetchPixelCacheNexusPixels(nexus_info,mode);
4978 return(nexus_info->pixels);
4982 Pixels are stored in a cache region until they are synced to the cache.
4984 number_pixels=(MagickSizeType) nexus_info->region.width*
4985 nexus_info->region.height;
4986 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
4987 if (cache_info->metacontent_extent != 0)
4988 length+=number_pixels*cache_info->metacontent_extent;
4989 if (nexus_info->cache == (Quantum *) NULL)
4991 nexus_info->length=length;
4992 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4993 if (status == MagickFalse)
4995 nexus_info->length=0;
4996 return((Quantum *) NULL);
5000 if (nexus_info->length != length)
5002 RelinquishCacheNexusPixels(nexus_info);
5003 nexus_info->length=length;
5004 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5005 if (status == MagickFalse)
5007 nexus_info->length=0;
5008 return((Quantum *) NULL);
5011 nexus_info->pixels=nexus_info->cache;
5012 nexus_info->metacontent=(void *) NULL;
5013 if (cache_info->metacontent_extent != 0)
5014 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
5015 cache_info->number_channels);
5016 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5017 return(nexus_info->pixels);
5021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5025 % 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 %
5029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5031 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5032 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5033 % access that is outside the boundaries of the image cache.
5035 % The format of the SetPixelCacheVirtualMethod() method is:
5037 % VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5038 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5040 % A description of each parameter follows:
5042 % o image: the image.
5044 % o virtual_pixel_method: choose the type of virtual pixel.
5046 % o exception: return any errors or warnings in this structure.
5050 static MagickBooleanType SetCacheAlphaChannel(Image *image,const Quantum alpha,
5051 ExceptionInfo *exception)
5065 assert(image != (Image *) NULL);
5066 assert(image->signature == MagickSignature);
5067 if (image->debug != MagickFalse)
5068 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5069 assert(image->cache != (Cache) NULL);
5070 cache_info=(CacheInfo *) image->cache;
5071 assert(cache_info->signature == MagickSignature);
5072 image->alpha_trait=BlendPixelTrait;
5074 image_view=AcquireVirtualCacheView(image,exception); /* must be virtual */
5075 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5076 #pragma omp parallel for schedule(static,4) shared(status) \
5077 magick_threads(image,image,1,1)
5079 for (y=0; y < (ssize_t) image->rows; y++)
5087 if (status == MagickFalse)
5089 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5090 if (q == (Quantum *) NULL)
5095 for (x=0; x < (ssize_t) image->columns; x++)
5097 SetPixelAlpha(image,alpha,q);
5098 q+=GetPixelChannels(image);
5100 status=SyncCacheViewAuthenticPixels(image_view,exception);
5102 image_view=DestroyCacheView(image_view);
5106 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(Image *image,
5107 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
5115 assert(image != (Image *) NULL);
5116 assert(image->signature == MagickSignature);
5117 if (image->debug != MagickFalse)
5118 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5119 assert(image->cache != (Cache) NULL);
5120 cache_info=(CacheInfo *) image->cache;
5121 assert(cache_info->signature == MagickSignature);
5122 method=cache_info->virtual_pixel_method;
5123 cache_info->virtual_pixel_method=virtual_pixel_method;
5124 if ((image->columns != 0) && (image->rows != 0))
5125 switch (virtual_pixel_method)
5127 case BackgroundVirtualPixelMethod:
5129 if ((image->background_color.alpha_trait == BlendPixelTrait) &&
5130 (image->alpha_trait != BlendPixelTrait))
5131 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5132 if ((IsPixelInfoGray(&image->background_color) == MagickFalse) &&
5133 (IsGrayColorspace(image->colorspace) != MagickFalse))
5134 (void) TransformImageColorspace(image,RGBColorspace,exception);
5137 case TransparentVirtualPixelMethod:
5139 if (image->alpha_trait != BlendPixelTrait)
5140 (void) SetCacheAlphaChannel(image,OpaqueAlpha,exception);
5150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5154 + 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 %
5158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5160 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5161 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5162 % is synced, otherwise MagickFalse.
5164 % The format of the SyncAuthenticPixelCacheNexus() method is:
5166 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5167 % NexusInfo *nexus_info,ExceptionInfo *exception)
5169 % A description of each parameter follows:
5171 % o image: the image.
5173 % o nexus_info: the cache nexus to sync.
5175 % o exception: return any errors or warnings in this structure.
5178 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5179 NexusInfo *nexus_info,ExceptionInfo *exception)
5188 Transfer pixels to the cache.
5190 assert(image != (Image *) NULL);
5191 assert(image->signature == MagickSignature);
5192 if (image->cache == (Cache) NULL)
5193 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5194 cache_info=(CacheInfo *) image->cache;
5195 assert(cache_info->signature == MagickSignature);
5196 if (cache_info->type == UndefinedCache)
5197 return(MagickFalse);
5198 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5200 assert(cache_info->signature == MagickSignature);
5201 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5202 if ((cache_info->metacontent_extent != 0) &&
5203 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5204 return(MagickFalse);
5209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5213 + S y n c A u t h e n t i c P i x e l C a c h e %
5217 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5219 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5220 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5221 % otherwise MagickFalse.
5223 % The format of the SyncAuthenticPixelsCache() method is:
5225 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5226 % ExceptionInfo *exception)
5228 % A description of each parameter follows:
5230 % o image: the image.
5232 % o exception: return any errors or warnings in this structure.
5235 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5236 ExceptionInfo *exception)
5242 id = GetOpenMPThreadId();
5247 assert(image != (Image *) NULL);
5248 assert(image->signature == MagickSignature);
5249 assert(image->cache != (Cache) NULL);
5250 cache_info=(CacheInfo *) image->cache;
5251 assert(cache_info->signature == MagickSignature);
5252 assert(id < (int) cache_info->number_threads);
5253 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5263 % S y n c A u t h e n t i c P i x e l s %
5267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5269 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5270 % The method returns MagickTrue if the pixel region is flushed, otherwise
5273 % The format of the SyncAuthenticPixels() method is:
5275 % MagickBooleanType SyncAuthenticPixels(Image *image,
5276 % ExceptionInfo *exception)
5278 % A description of each parameter follows:
5280 % o image: the image.
5282 % o exception: return any errors or warnings in this structure.
5285 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5286 ExceptionInfo *exception)
5292 id = GetOpenMPThreadId();
5297 assert(image != (Image *) NULL);
5298 assert(image->signature == MagickSignature);
5299 assert(image->cache != (Cache) NULL);
5300 cache_info=(CacheInfo *) image->cache;
5301 assert(cache_info->signature == MagickSignature);
5302 if (cache_info->methods.sync_authentic_pixels_handler !=
5303 (SyncAuthenticPixelsHandler) NULL)
5305 status=cache_info->methods.sync_authentic_pixels_handler(image,
5309 assert(id < (int) cache_info->number_threads);
5310 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5320 + S y n c I m a g e P i x e l C a c h e %
5324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5326 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5327 % The method returns MagickTrue if the pixel region is flushed, otherwise
5330 % The format of the SyncImagePixelCache() method is:
5332 % MagickBooleanType SyncImagePixelCache(Image *image,
5333 % ExceptionInfo *exception)
5335 % A description of each parameter follows:
5337 % o image: the image.
5339 % o exception: return any errors or warnings in this structure.
5342 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5343 ExceptionInfo *exception)
5348 assert(image != (Image *) NULL);
5349 assert(exception != (ExceptionInfo *) NULL);
5350 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5351 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5359 + 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 %
5363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5365 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5366 % of the pixel cache.
5368 % The format of the WritePixelCacheMetacontent() method is:
5370 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5371 % NexusInfo *nexus_info,ExceptionInfo *exception)
5373 % A description of each parameter follows:
5375 % o cache_info: the pixel cache.
5377 % o nexus_info: the cache nexus to write the meta-content.
5379 % o exception: return any errors or warnings in this structure.
5382 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5383 NexusInfo *nexus_info,ExceptionInfo *exception)
5393 register const unsigned char
5402 if (cache_info->metacontent_extent == 0)
5403 return(MagickFalse);
5404 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5406 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5407 nexus_info->region.x;
5408 length=(MagickSizeType) nexus_info->region.width*
5409 cache_info->metacontent_extent;
5410 rows=nexus_info->region.height;
5411 extent=(MagickSizeType) length*rows;
5412 p=(unsigned char *) nexus_info->metacontent;
5413 switch (cache_info->type)
5418 register unsigned char
5422 Write associated pixels to memory.
5424 if ((cache_info->columns == nexus_info->region.width) &&
5425 (extent == (MagickSizeType) ((size_t) extent)))
5430 q=(unsigned char *) cache_info->metacontent+offset*
5431 cache_info->metacontent_extent;
5432 for (y=0; y < (ssize_t) rows; y++)
5434 (void) memcpy(q,p,(size_t) length);
5435 p+=nexus_info->region.width*cache_info->metacontent_extent;
5436 q+=cache_info->columns*cache_info->metacontent_extent;
5443 Write associated pixels to disk.
5445 LockSemaphoreInfo(cache_info->file_semaphore);
5446 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5448 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5449 cache_info->cache_filename);
5450 UnlockSemaphoreInfo(cache_info->file_semaphore);
5451 return(MagickFalse);
5453 if ((cache_info->columns == nexus_info->region.width) &&
5454 (extent <= MagickMaxBufferExtent))
5459 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5460 for (y=0; y < (ssize_t) rows; y++)
5462 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5463 cache_info->number_channels*sizeof(Quantum)+offset*
5464 cache_info->metacontent_extent,length,(const unsigned char *) p);
5465 if ((MagickSizeType) count != length)
5467 p+=nexus_info->region.width*cache_info->metacontent_extent;
5468 offset+=cache_info->columns;
5470 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5471 (void) ClosePixelCacheOnDisk(cache_info);
5472 UnlockSemaphoreInfo(cache_info->file_semaphore);
5473 if (y < (ssize_t) rows)
5475 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5476 cache_info->cache_filename);
5477 return(MagickFalse);
5481 case DistributedCache:
5489 if ((cache_info->debug != MagickFalse) &&
5490 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5491 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5492 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5493 nexus_info->region.width,(double) nexus_info->region.height,(double)
5494 nexus_info->region.x,(double) nexus_info->region.y);
5499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5503 + W r i t e C a c h e P i x e l s %
5507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5509 % WritePixelCachePixels() writes image pixels to the specified region of the
5512 % The format of the WritePixelCachePixels() method is:
5514 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5515 % NexusInfo *nexus_info,ExceptionInfo *exception)
5517 % A description of each parameter follows:
5519 % o cache_info: the pixel cache.
5521 % o nexus_info: the cache nexus to write the pixels.
5523 % o exception: return any errors or warnings in this structure.
5526 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5527 NexusInfo *nexus_info,ExceptionInfo *exception)
5537 register const Quantum
5546 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5548 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5549 nexus_info->region.x;
5550 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5552 rows=nexus_info->region.height;
5554 p=nexus_info->pixels;
5555 switch (cache_info->type)
5564 Write pixels to memory.
5566 if ((cache_info->columns == nexus_info->region.width) &&
5567 (extent == (MagickSizeType) ((size_t) extent)))
5572 q=cache_info->pixels+offset*cache_info->number_channels;
5573 for (y=0; y < (ssize_t) rows; y++)
5575 (void) memcpy(q,p,(size_t) length);
5576 p+=nexus_info->region.width*cache_info->number_channels;
5577 q+=cache_info->columns*cache_info->number_channels;
5584 Write pixels to disk.
5586 LockSemaphoreInfo(cache_info->file_semaphore);
5587 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5589 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5590 cache_info->cache_filename);
5591 UnlockSemaphoreInfo(cache_info->file_semaphore);
5592 return(MagickFalse);
5594 if ((cache_info->columns == nexus_info->region.width) &&
5595 (extent <= MagickMaxBufferExtent))
5600 for (y=0; y < (ssize_t) rows; y++)
5602 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5603 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5605 if ((MagickSizeType) count != length)
5607 p+=nexus_info->region.width*cache_info->number_channels;
5608 offset+=cache_info->columns;
5610 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5611 (void) ClosePixelCacheOnDisk(cache_info);
5612 UnlockSemaphoreInfo(cache_info->file_semaphore);
5613 if (y < (ssize_t) rows)
5615 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5616 cache_info->cache_filename);
5617 return(MagickFalse);
5621 case DistributedCache:
5629 if ((cache_info->debug != MagickFalse) &&
5630 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5631 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5632 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5633 nexus_info->region.width,(double) nexus_info->region.height,(double)
5634 nexus_info->region.x,(double) nexus_info->region.y);