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-2011 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/composite-private.h"
50 #include "MagickCore/exception.h"
51 #include "MagickCore/exception-private.h"
52 #include "MagickCore/geometry.h"
53 #include "MagickCore/list.h"
54 #include "MagickCore/log.h"
55 #include "MagickCore/magick.h"
56 #include "MagickCore/memory_.h"
57 #include "MagickCore/pixel.h"
58 #include "MagickCore/pixel-accessor.h"
59 #include "MagickCore/policy.h"
60 #include "MagickCore/quantum.h"
61 #include "MagickCore/random_.h"
62 #include "MagickCore/resource_.h"
63 #include "MagickCore/semaphore.h"
64 #include "MagickCore/splay-tree.h"
65 #include "MagickCore/string_.h"
66 #include "MagickCore/string-private.h"
67 #include "MagickCore/thread-private.h"
68 #include "MagickCore/utility.h"
69 #include "MagickCore/utility-private.h"
70 #if defined(MAGICKCORE_ZLIB_DELEGATE)
77 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
82 typedef struct _MagickModulo
112 Forward declarations.
114 #if defined(__cplusplus) || defined(c_plusplus)
119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
121 *GetVirtualPixelsCache(const Image *);
124 *GetVirtualMetacontentFromCache(const Image *);
126 static MagickBooleanType
127 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
128 Quantum *,ExceptionInfo *),
129 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
130 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
131 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
132 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
134 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
135 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
136 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
139 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
140 const size_t,ExceptionInfo *),
141 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
143 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
146 #if defined(__cplusplus) || defined(c_plusplus)
153 static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
157 *cache_semaphore = (SemaphoreInfo *) NULL;
160 *cache_resources = (SplayTreeInfo *) NULL;
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167 + A c q u i r e P i x e l C a c h e %
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173 % AcquirePixelCache() acquires a pixel cache.
175 % The format of the AcquirePixelCache() method is:
177 % Cache AcquirePixelCache(const size_t number_threads)
179 % A description of each parameter follows:
181 % o number_threads: the number of nexus threads.
184 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
189 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
190 if (cache_info == (CacheInfo *) NULL)
191 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
192 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
193 cache_info->type=UndefinedCache;
194 cache_info->mode=IOMode;
195 cache_info->colorspace=RGBColorspace;
196 cache_info->file=(-1);
197 cache_info->id=GetMagickThreadId();
198 cache_info->number_threads=number_threads;
199 if (number_threads == 0)
200 cache_info->number_threads=GetOpenMPMaximumThreads();
201 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202 if (cache_info->nexus_info == (NexusInfo **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204 cache_info->semaphore=AllocateSemaphoreInfo();
205 cache_info->reference_count=1;
206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
214 LockSemaphoreInfo(cache_semaphore);
215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
222 UnlockSemaphoreInfo(cache_semaphore);
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 % A c q u i r e P i x e l C a c h e N e x u s %
237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
241 % The format of the AcquirePixelCacheNexus method is:
243 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
245 % A description of each parameter follows:
247 % o number_threads: the number of nexus threads.
250 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
258 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
262 for (i=0; i < (ssize_t) number_threads; i++)
264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
278 + A c q u i r e P i x e l C a c h e P i x e l s %
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284 % AcquirePixelCachePixels() returns the pixels associated with the specified
287 % The format of the AcquirePixelCachePixels() method is:
289 % const void *AcquirePixelCachePixels(const Image *image,
290 % MagickSizeType *length,ExceptionInfo *exception)
292 % A description of each parameter follows:
294 % o image: the image.
296 % o length: the pixel cache length.
298 % o exception: return any errors or warnings in this structure.
301 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
302 MagickSizeType *length,ExceptionInfo *exception)
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326 + C a c h e C o m p o n e n t G e n e s i s %
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332 % CacheComponentGenesis() instantiates the cache component.
334 % The format of the CacheComponentGenesis method is:
336 % MagickBooleanType CacheComponentGenesis(void)
339 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
341 AcquireSemaphoreInfo(&cache_semaphore);
346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 + C a c h e C o m p o n e n t T e r m i n u s %
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356 % CacheComponentTerminus() destroys the cache component.
358 % The format of the CacheComponentTerminus() method is:
360 % CacheComponentTerminus(void)
363 MagickPrivate void CacheComponentTerminus(void)
365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
367 LockSemaphoreInfo(cache_semaphore);
368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
371 UnlockSemaphoreInfo(cache_semaphore);
372 DestroySemaphoreInfo(&cache_semaphore);
376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380 + C l i p P i x e l C a c h e N e x u s %
384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 % ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
387 % mask. It returns MagickTrue if the pixel region is clipped, otherwise
390 % The format of the ClipPixelCacheNexus() method is:
392 % MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393 % ExceptionInfo *exception)
395 % A description of each parameter follows:
397 % o image: the image.
399 % o nexus_info: the cache nexus to clip.
401 % o exception: return any errors or warnings in this structure.
404 static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
417 register const Quantum
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432 if (image->clip_mask == (Image *) NULL)
434 cache_info=(CacheInfo *) image->cache;
435 if (cache_info == (Cache) NULL)
437 image_nexus=AcquirePixelCacheNexus(1);
438 clip_nexus=AcquirePixelCacheNexus(1);
439 if ((image_nexus == (NexusInfo **) NULL) ||
440 (clip_nexus == (NexusInfo **) NULL))
441 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
442 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
443 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
444 nexus_info->region.height,image_nexus[0],exception);
445 q=nexus_info->pixels;
446 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
447 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
448 nexus_info->region.height,clip_nexus[0],exception);
449 number_pixels=(MagickSizeType) nexus_info->region.width*
450 nexus_info->region.height;
451 for (i=0; i < (ssize_t) number_pixels; i++)
453 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
455 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
457 SetPixelRed(image,GetPixelRed(image,p),q);
458 SetPixelGreen(image,GetPixelGreen(image,p),q);
459 SetPixelBlue(image,GetPixelBlue(image,p),q);
460 if (cache_info->colorspace == CMYKColorspace)
461 SetPixelBlack(image,GetPixelBlack(image,p),q);
462 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
464 p+=GetPixelChannels(image);
465 q+=GetPixelChannels(image);
466 r+=GetPixelChannels(image->clip_mask);
468 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
469 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
470 if (i < (ssize_t) number_pixels)
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
480 + C l o n e P i x e l C a c h e %
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486 % ClonePixelCache() clones a pixel cache.
488 % The format of the ClonePixelCache() method is:
490 % Cache ClonePixelCache(const Cache cache)
492 % A description of each parameter follows:
494 % o cache: the pixel cache.
497 MagickPrivate Cache ClonePixelCache(const Cache cache)
505 assert(cache != NULL);
506 cache_info=(const CacheInfo *) cache;
507 assert(cache_info->signature == MagickSignature);
508 if (cache_info->debug != MagickFalse)
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
510 cache_info->filename);
511 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
512 if (clone_info == (Cache) NULL)
513 return((Cache) NULL);
514 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
515 return((Cache ) clone_info);
519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
523 + C l o n e P i x e l C a c h e P i x e l s %
527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
528 % ClonePixelCachePixels() clones the source pixel cache to the destination
531 % The format of the ClonePixelCachePixels() method is:
533 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
534 % CacheInfo *source_info,ExceptionInfo *exception)
536 % A description of each parameter follows:
538 % o cache_info: the pixel cache.
540 % o source_info: the source pixel cache.
542 % o exception: return any errors or warnings in this structure.
546 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
552 LockSemaphoreInfo(cache_info->disk_semaphore);
553 if (cache_info->file != -1)
555 status=close(cache_info->file);
556 cache_info->file=(-1);
557 RelinquishMagickResource(FileResource,1);
559 UnlockSemaphoreInfo(cache_info->disk_semaphore);
560 return(status == -1 ? MagickFalse : MagickTrue);
563 static void LimitPixelCacheDescriptors(void)
570 Limit # of open file descriptors.
572 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
574 LockSemaphoreInfo(cache_semaphore);
575 if (cache_resources == (SplayTreeInfo *) NULL)
577 UnlockSemaphoreInfo(cache_semaphore);
580 ResetSplayTreeIterator(cache_resources);
581 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
582 while (p != (CacheInfo *) NULL)
584 if ((p->type == DiskCache) && (p->file != -1))
586 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
588 for (q=p; p != (CacheInfo *) NULL; )
590 if ((p->type == DiskCache) && (p->file != -1) &&
591 (p->timestamp < q->timestamp))
593 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
595 if (q != (CacheInfo *) NULL)
598 Close least recently used cache.
600 (void) close(q->file);
603 UnlockSemaphoreInfo(cache_semaphore);
606 static inline MagickSizeType MagickMax(const MagickSizeType x,
607 const MagickSizeType y)
614 static inline MagickSizeType MagickMin(const MagickSizeType x,
615 const MagickSizeType y)
622 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
629 Open pixel cache on disk.
631 LockSemaphoreInfo(cache_info->disk_semaphore);
632 if (cache_info->file != -1)
634 UnlockSemaphoreInfo(cache_info->disk_semaphore);
635 return(MagickTrue); /* cache already open */
637 LimitPixelCacheDescriptors();
638 if (*cache_info->cache_filename == '\0')
639 file=AcquireUniqueFileResource(cache_info->cache_filename);
645 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
650 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
651 O_BINARY | O_EXCL,S_MODE);
653 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
659 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
662 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
668 UnlockSemaphoreInfo(cache_info->disk_semaphore);
671 (void) AcquireMagickResource(FileResource,1);
672 cache_info->file=file;
673 cache_info->timestamp=time(0);
674 UnlockSemaphoreInfo(cache_info->disk_semaphore);
678 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
679 const MagickOffsetType offset,const MagickSizeType length,
680 unsigned char *restrict buffer)
682 register MagickOffsetType
688 cache_info->timestamp=time(0);
689 #if !defined(MAGICKCORE_HAVE_PREAD)
690 LockSemaphoreInfo(cache_info->disk_semaphore);
691 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
693 UnlockSemaphoreInfo(cache_info->disk_semaphore);
694 return((MagickOffsetType) -1);
698 for (i=0; i < (MagickOffsetType) length; i+=count)
700 #if !defined(MAGICKCORE_HAVE_PREAD)
701 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
702 (MagickSizeType) SSIZE_MAX));
704 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
716 #if !defined(MAGICKCORE_HAVE_PREAD)
717 UnlockSemaphoreInfo(cache_info->disk_semaphore);
722 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
723 const MagickOffsetType offset,const MagickSizeType length,
724 const unsigned char *restrict buffer)
726 register MagickOffsetType
732 cache_info->timestamp=time(0);
733 #if !defined(MAGICKCORE_HAVE_PWRITE)
734 LockSemaphoreInfo(cache_info->disk_semaphore);
735 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
737 UnlockSemaphoreInfo(cache_info->disk_semaphore);
738 return((MagickOffsetType) -1);
742 for (i=0; i < (MagickOffsetType) length; i+=count)
744 #if !defined(MAGICKCORE_HAVE_PWRITE)
745 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
746 (MagickSizeType) SSIZE_MAX));
748 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
760 #if !defined(MAGICKCORE_HAVE_PWRITE)
761 UnlockSemaphoreInfo(cache_info->disk_semaphore);
766 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
767 CacheInfo *cache_info,ExceptionInfo *exception)
772 register MagickOffsetType
782 Clone pixel cache (both caches on disk).
784 if (cache_info->debug != MagickFalse)
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
786 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
788 if (blob == (unsigned char *) NULL)
790 (void) ThrowMagickException(exception,GetMagickModule(),
791 ResourceLimitError,"MemoryAllocationFailed","`%s'",
792 cache_info->filename);
795 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
797 blob=(unsigned char *) RelinquishMagickMemory(blob);
798 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
799 cache_info->cache_filename);
802 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
804 (void) ClosePixelCacheOnDisk(cache_info);
805 blob=(unsigned char *) RelinquishMagickMemory(blob);
806 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
807 clone_info->cache_filename);
811 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
813 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
814 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
818 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
819 cache_info->cache_filename);
822 length=(size_t) count;
823 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
824 if ((MagickSizeType) count != length)
826 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
827 clone_info->cache_filename);
831 (void) ClosePixelCacheOnDisk(clone_info);
832 (void) ClosePixelCacheOnDisk(cache_info);
833 blob=(unsigned char *) RelinquishMagickMemory(blob);
834 if (i < (MagickOffsetType) cache_info->length)
839 static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
840 CacheInfo *cache_info,ExceptionInfo *exception)
845 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
848 Clone pixel cache (both caches in memory).
850 if (cache_info->debug != MagickFalse)
851 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
852 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
856 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
859 Clone pixel cache (one cache on disk, one in memory).
861 if (cache_info->debug != MagickFalse)
862 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
863 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
865 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
866 cache_info->cache_filename);
869 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
870 cache_info->length,(unsigned char *) clone_info->pixels);
871 (void) ClosePixelCacheOnDisk(cache_info);
872 if ((MagickSizeType) count != cache_info->length)
874 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
875 cache_info->cache_filename);
880 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
883 Clone pixel cache (one cache on disk, one in memory).
885 if (clone_info->debug != MagickFalse)
886 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
887 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
889 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
890 clone_info->cache_filename);
893 count=WritePixelCacheRegion(clone_info,clone_info->offset,
894 clone_info->length,(unsigned char *) cache_info->pixels);
895 (void) ClosePixelCacheOnDisk(clone_info);
896 if ((MagickSizeType) count != clone_info->length)
898 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
899 clone_info->cache_filename);
905 Clone pixel cache (both caches on disk).
907 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
910 static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
911 CacheInfo *cache_info,ExceptionInfo *exception)
934 Clone pixel cache (unoptimized).
936 if (cache_info->debug != MagickFalse)
938 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
939 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
941 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
942 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
944 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
945 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
947 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
949 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
950 clone_info->number_channels)*sizeof(Quantum),MagickMax(
951 cache_info->metacontent_extent,clone_info->metacontent_extent));
952 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
953 if (blob == (unsigned char *) NULL)
955 (void) ThrowMagickException(exception,GetMagickModule(),
956 ResourceLimitError,"MemoryAllocationFailed","`%s'",
957 cache_info->filename);
960 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
963 if (cache_info->type == DiskCache)
965 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
967 blob=(unsigned char *) RelinquishMagickMemory(blob);
968 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
969 cache_info->cache_filename);
972 cache_offset=cache_info->offset;
974 if (clone_info->type == DiskCache)
976 if ((cache_info->type == DiskCache) &&
977 (strcmp(cache_info->cache_filename,clone_info->cache_filename) == 0))
979 (void) ClosePixelCacheOnDisk(clone_info);
980 *clone_info->cache_filename='\0';
982 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
984 if (cache_info->type == DiskCache)
985 (void) ClosePixelCacheOnDisk(cache_info);
986 blob=(unsigned char *) RelinquishMagickMemory(blob);
987 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
988 clone_info->cache_filename);
991 clone_offset=clone_info->offset;
994 Clone pixel channels.
997 for (y=0; y < (ssize_t) cache_info->rows; y++)
999 for (x=0; x < (ssize_t) cache_info->columns; x++)
1002 Read a set of pixel channels.
1004 length=cache_info->number_channels*sizeof(Quantum);
1005 if (cache_info->type != DiskCache)
1006 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1010 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1011 if ((MagickSizeType) count != length)
1017 cache_offset+=length;
1018 if ((y < (ssize_t) clone_info->rows) &&
1019 (x < (ssize_t) clone_info->columns))
1022 Write a set of pixel channels.
1024 length=clone_info->number_channels*sizeof(Quantum);
1025 if (clone_info->type != DiskCache)
1026 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1030 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1031 if ((MagickSizeType) count != length)
1037 clone_offset+=length;
1040 length=clone_info->number_channels*sizeof(Quantum);
1041 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1042 for ( ; x < (ssize_t) clone_info->columns; x++)
1045 Set remaining columns with transparent pixel channels.
1047 if (clone_info->type != DiskCache)
1048 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1052 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1053 if ((MagickSizeType) count != length)
1059 clone_offset+=length;
1062 length=clone_info->number_channels*sizeof(Quantum);
1063 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1064 for ( ; y < (ssize_t) clone_info->rows; y++)
1067 Set remaining rows with transparent pixels.
1069 for (x=0; x < (ssize_t) clone_info->columns; x++)
1071 if (clone_info->type != DiskCache)
1072 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1076 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1077 if ((MagickSizeType) count != length)
1083 clone_offset+=length;
1086 if ((cache_info->metacontent_extent != 0) &&
1087 (clone_info->metacontent_extent != 0))
1092 for (y=0; y < (ssize_t) cache_info->rows; y++)
1094 for (x=0; x < (ssize_t) cache_info->columns; x++)
1097 Read a set of metacontent.
1099 length=cache_info->metacontent_extent;
1100 if (cache_info->type != DiskCache)
1101 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1102 cache_offset,length);
1105 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1106 if ((MagickSizeType) count != length)
1112 cache_offset+=length;
1113 if ((y < (ssize_t) clone_info->rows) &&
1114 (x < (ssize_t) clone_info->columns))
1117 Write a set of metacontent.
1119 length=clone_info->metacontent_extent;
1120 if (clone_info->type != DiskCache)
1121 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1125 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1127 if ((MagickSizeType) count != length)
1133 clone_offset+=length;
1136 length=clone_info->metacontent_extent;
1137 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1138 for ( ; x < (ssize_t) clone_info->columns; x++)
1141 Set remaining columns with metacontent.
1143 if (clone_info->type != DiskCache)
1144 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1148 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1149 if ((MagickSizeType) count != length)
1155 clone_offset+=length;
1158 length=clone_info->metacontent_extent;
1159 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1160 for ( ; y < (ssize_t) clone_info->rows; y++)
1163 Set remaining rows with metacontent.
1165 for (x=0; x < (ssize_t) clone_info->columns; x++)
1167 if (clone_info->type != DiskCache)
1168 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1172 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1173 if ((MagickSizeType) count != length)
1179 clone_offset+=length;
1183 if (clone_info->type == DiskCache)
1184 (void) ClosePixelCacheOnDisk(clone_info);
1185 if (cache_info->type == DiskCache)
1186 (void) ClosePixelCacheOnDisk(cache_info);
1187 blob=(unsigned char *) RelinquishMagickMemory(blob);
1191 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1192 CacheInfo *cache_info,ExceptionInfo *exception)
1194 if (cache_info->type == PingCache)
1196 if ((cache_info->columns == clone_info->columns) &&
1197 (cache_info->rows == clone_info->rows) &&
1198 (cache_info->number_channels == clone_info->number_channels) &&
1199 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1200 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1201 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
1205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1209 + C l o n e P i x e l C a c h e M e t h o d s %
1213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1218 % The format of the ClonePixelCacheMethods() method is:
1220 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1222 % A description of each parameter follows:
1224 % o clone: Specifies a pointer to a Cache structure.
1226 % o cache: the pixel cache.
1229 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1235 assert(clone != (Cache) NULL);
1236 source_info=(CacheInfo *) clone;
1237 assert(source_info->signature == MagickSignature);
1238 if (source_info->debug != MagickFalse)
1239 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1240 source_info->filename);
1241 assert(cache != (Cache) NULL);
1242 cache_info=(CacheInfo *) cache;
1243 assert(cache_info->signature == MagickSignature);
1244 source_info->methods=cache_info->methods;
1248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252 + D e s t r o y I m a g e P i x e l C a c h e %
1256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1260 % The format of the DestroyImagePixelCache() method is:
1262 % void DestroyImagePixelCache(Image *image)
1264 % A description of each parameter follows:
1266 % o image: the image.
1269 static void DestroyImagePixelCache(Image *image)
1271 assert(image != (Image *) NULL);
1272 assert(image->signature == MagickSignature);
1273 if (image->debug != MagickFalse)
1274 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1275 if (image->cache == (void *) NULL)
1277 image->cache=DestroyPixelCache(image->cache);
1281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1285 + D e s t r o y I m a g e P i x e l s %
1289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1291 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1293 % The format of the DestroyImagePixels() method is:
1295 % void DestroyImagePixels(Image *image)
1297 % A description of each parameter follows:
1299 % o image: the image.
1302 MagickExport void DestroyImagePixels(Image *image)
1307 assert(image != (const Image *) NULL);
1308 assert(image->signature == MagickSignature);
1309 if (image->debug != MagickFalse)
1310 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1311 assert(image->cache != (Cache) NULL);
1312 cache_info=(CacheInfo *) image->cache;
1313 assert(cache_info->signature == MagickSignature);
1314 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1316 cache_info->methods.destroy_pixel_handler(image);
1319 image->cache=DestroyPixelCache(image->cache);
1323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1327 + D e s t r o y P i x e l C a c h e %
1331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1335 % The format of the DestroyPixelCache() method is:
1337 % Cache DestroyPixelCache(Cache cache)
1339 % A description of each parameter follows:
1341 % o cache: the pixel cache.
1345 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1347 switch (cache_info->type)
1351 if (cache_info->mapped == MagickFalse)
1352 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
1353 cache_info->pixels);
1355 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1356 (size_t) cache_info->length);
1357 RelinquishMagickResource(MemoryResource,cache_info->length);
1362 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1363 cache_info->length);
1364 RelinquishMagickResource(MapResource,cache_info->length);
1368 if (cache_info->file != -1)
1369 (void) ClosePixelCacheOnDisk(cache_info);
1370 RelinquishMagickResource(DiskResource,cache_info->length);
1376 cache_info->type=UndefinedCache;
1377 cache_info->mapped=MagickFalse;
1378 cache_info->metacontent=(void *) NULL;
1381 MagickPrivate Cache DestroyPixelCache(Cache cache)
1386 assert(cache != (Cache) NULL);
1387 cache_info=(CacheInfo *) cache;
1388 assert(cache_info->signature == MagickSignature);
1389 if (cache_info->debug != MagickFalse)
1390 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1391 cache_info->filename);
1392 LockSemaphoreInfo(cache_info->semaphore);
1393 cache_info->reference_count--;
1394 if (cache_info->reference_count != 0)
1396 UnlockSemaphoreInfo(cache_info->semaphore);
1397 return((Cache) NULL);
1399 UnlockSemaphoreInfo(cache_info->semaphore);
1400 if (cache_resources != (SplayTreeInfo *) NULL)
1401 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1402 if (cache_info->debug != MagickFalse)
1405 message[MaxTextExtent];
1407 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1408 cache_info->filename);
1409 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1411 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1412 (cache_info->type != DiskCache)))
1413 RelinquishPixelCachePixels(cache_info);
1416 RelinquishPixelCachePixels(cache_info);
1417 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1419 *cache_info->cache_filename='\0';
1420 if (cache_info->nexus_info != (NexusInfo **) NULL)
1421 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1422 cache_info->number_threads);
1423 if (cache_info->random_info != (RandomInfo *) NULL)
1424 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1425 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1426 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1427 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1428 DestroySemaphoreInfo(&cache_info->semaphore);
1429 cache_info->signature=(~MagickSignature);
1430 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1436 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1440 + D e s t r o y P i x e l C a c h e N e x u s %
1444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1446 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1448 % The format of the DestroyPixelCacheNexus() method is:
1450 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1451 % const size_t number_threads)
1453 % A description of each parameter follows:
1455 % o nexus_info: the nexus to destroy.
1457 % o number_threads: the number of nexus threads.
1461 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1463 if (nexus_info->mapped == MagickFalse)
1464 (void) RelinquishMagickMemory(nexus_info->cache);
1466 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1467 nexus_info->cache=(Quantum *) NULL;
1468 nexus_info->pixels=(Quantum *) NULL;
1469 nexus_info->metacontent=(void *) NULL;
1470 nexus_info->length=0;
1471 nexus_info->mapped=MagickFalse;
1474 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1475 const size_t number_threads)
1480 assert(nexus_info != (NexusInfo **) NULL);
1481 for (i=0; i < (ssize_t) number_threads; i++)
1483 if (nexus_info[i]->cache != (Quantum *) NULL)
1484 RelinquishCacheNexusPixels(nexus_info[i]);
1485 nexus_info[i]->signature=(~MagickSignature);
1486 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1488 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1497 % G e t A u t h e n t i c M e t a c o n t e n t %
1501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1503 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1504 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1505 % returned if the associated pixels are not available.
1507 % The format of the GetAuthenticMetacontent() method is:
1509 % void *GetAuthenticMetacontent(const Image *image)
1511 % A description of each parameter follows:
1513 % o image: the image.
1516 MagickExport void *GetAuthenticMetacontent(const Image *image)
1522 id = GetOpenMPThreadId();
1527 assert(image != (const Image *) NULL);
1528 assert(image->signature == MagickSignature);
1529 assert(image->cache != (Cache) NULL);
1530 cache_info=(CacheInfo *) image->cache;
1531 assert(cache_info->signature == MagickSignature);
1532 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1533 (GetAuthenticMetacontentFromHandler) NULL)
1535 metacontent=cache_info->methods.
1536 get_authentic_metacontent_from_handler(image);
1537 return(metacontent);
1539 assert(id < (int) cache_info->number_threads);
1540 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1541 cache_info->nexus_info[id]);
1542 return(metacontent);
1546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1550 + 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 %
1554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1556 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1557 % with the last call to QueueAuthenticPixelsCache() or
1558 % GetAuthenticPixelsCache().
1560 % The format of the GetAuthenticMetacontentFromCache() method is:
1562 % void *GetAuthenticMetacontentFromCache(const Image *image)
1564 % A description of each parameter follows:
1566 % o image: the image.
1569 static void *GetAuthenticMetacontentFromCache(const Image *image)
1575 id = GetOpenMPThreadId();
1580 assert(image != (const Image *) NULL);
1581 assert(image->signature == MagickSignature);
1582 assert(image->cache != (Cache) NULL);
1583 cache_info=(CacheInfo *) image->cache;
1584 assert(cache_info->signature == MagickSignature);
1585 assert(id < (int) cache_info->number_threads);
1586 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1587 cache_info->nexus_info[id]);
1588 return(metacontent);
1592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596 + 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 %
1600 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1602 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1603 % disk pixel cache as defined by the geometry parameters. A pointer to the
1604 % pixels is returned if the pixels are transferred, otherwise a NULL is
1607 % The format of the GetAuthenticPixelCacheNexus() method is:
1609 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1610 % const ssize_t y,const size_t columns,const size_t rows,
1611 % NexusInfo *nexus_info,ExceptionInfo *exception)
1613 % A description of each parameter follows:
1615 % o image: the image.
1617 % o x,y,columns,rows: These values define the perimeter of a region of
1620 % o nexus_info: the cache nexus to return.
1622 % o exception: return any errors or warnings in this structure.
1626 static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
1627 NexusInfo *nexus_info)
1635 if (cache_info->type == PingCache)
1637 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1638 nexus_info->region.x;
1639 status=nexus_info->pixels == (cache_info->pixels+offset*
1640 cache_info->number_channels) ? MagickTrue : MagickFalse;
1644 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1645 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1646 NexusInfo *nexus_info,ExceptionInfo *exception)
1655 Transfer pixels from the cache.
1657 assert(image != (Image *) NULL);
1658 assert(image->signature == MagickSignature);
1659 q=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1660 if (q == (Quantum *) NULL)
1661 return((Quantum *) NULL);
1662 cache_info=(CacheInfo *) image->cache;
1663 assert(cache_info->signature == MagickSignature);
1664 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1666 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1667 return((Quantum *) NULL);
1668 if (cache_info->metacontent_extent != 0)
1669 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1670 return((Quantum *) NULL);
1675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1679 + 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 %
1683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1686 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1688 % The format of the GetAuthenticPixelsFromCache() method is:
1690 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1692 % A description of each parameter follows:
1694 % o image: the image.
1697 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1703 id = GetOpenMPThreadId();
1705 assert(image != (const Image *) NULL);
1706 assert(image->signature == MagickSignature);
1707 assert(image->cache != (Cache) NULL);
1708 cache_info=(CacheInfo *) image->cache;
1709 assert(cache_info->signature == MagickSignature);
1710 assert(id < (int) cache_info->number_threads);
1711 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1719 % G e t A u t h e n t i c P i x e l Q u e u e %
1723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1725 % GetAuthenticPixelQueue() returns the authentic pixels associated
1726 % corresponding with the last call to QueueAuthenticPixels() or
1727 % GetAuthenticPixels().
1729 % The format of the GetAuthenticPixelQueue() method is:
1731 % Quantum *GetAuthenticPixelQueue(const Image image)
1733 % A description of each parameter follows:
1735 % o image: the image.
1738 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1744 id = GetOpenMPThreadId();
1746 assert(image != (const Image *) NULL);
1747 assert(image->signature == MagickSignature);
1748 assert(image->cache != (Cache) NULL);
1749 cache_info=(CacheInfo *) image->cache;
1750 assert(cache_info->signature == MagickSignature);
1751 if (cache_info->methods.get_authentic_pixels_from_handler !=
1752 (GetAuthenticPixelsFromHandler) NULL)
1753 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1754 assert(id < (int) cache_info->number_threads);
1755 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763 % G e t A u t h e n t i c P i x e l s %
1766 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1768 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1769 % region is successfully accessed, a pointer to a Quantum array
1770 % representing the region is returned, otherwise NULL is returned.
1772 % The returned pointer may point to a temporary working copy of the pixels
1773 % or it may point to the original pixels in memory. Performance is maximized
1774 % if the selected region is part of one row, or one or more full rows, since
1775 % then there is opportunity to access the pixels in-place (without a copy)
1776 % if the image is in memory, or in a memory-mapped file. The returned pointer
1777 % must *never* be deallocated by the user.
1779 % Pixels accessed via the returned pointer represent a simple array of type
1780 % Quantum. If the image has corresponding metacontent,call
1781 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1782 % meta-content corresponding to the region. Once the Quantum array has
1783 % been updated, the changes must be saved back to the underlying image using
1784 % SyncAuthenticPixels() or they may be lost.
1786 % The format of the GetAuthenticPixels() method is:
1788 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1789 % const ssize_t y,const size_t columns,const size_t rows,
1790 % ExceptionInfo *exception)
1792 % A description of each parameter follows:
1794 % o image: the image.
1796 % o x,y,columns,rows: These values define the perimeter of a region of
1799 % o exception: return any errors or warnings in this structure.
1802 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1803 const ssize_t y,const size_t columns,const size_t rows,
1804 ExceptionInfo *exception)
1810 id = GetOpenMPThreadId();
1815 assert(image != (Image *) NULL);
1816 assert(image->signature == MagickSignature);
1817 assert(image->cache != (Cache) NULL);
1818 cache_info=(CacheInfo *) image->cache;
1819 assert(cache_info->signature == MagickSignature);
1820 if (cache_info->methods.get_authentic_pixels_handler !=
1821 (GetAuthenticPixelsHandler) NULL)
1823 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1827 assert(id < (int) cache_info->number_threads);
1828 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1829 cache_info->nexus_info[id],exception);
1834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1838 + G e t A u t h e n t i c P i x e l s C a c h e %
1842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1844 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1845 % as defined by the geometry parameters. A pointer to the pixels is returned
1846 % if the pixels are transferred, otherwise a NULL is returned.
1848 % The format of the GetAuthenticPixelsCache() method is:
1850 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1851 % const ssize_t y,const size_t columns,const size_t rows,
1852 % ExceptionInfo *exception)
1854 % A description of each parameter follows:
1856 % o image: the image.
1858 % o x,y,columns,rows: These values define the perimeter of a region of
1861 % o exception: return any errors or warnings in this structure.
1864 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1865 const ssize_t y,const size_t columns,const size_t rows,
1866 ExceptionInfo *exception)
1872 id = GetOpenMPThreadId();
1877 assert(image != (const Image *) NULL);
1878 assert(image->signature == MagickSignature);
1879 assert(image->cache != (Cache) NULL);
1880 cache_info=(CacheInfo *) image->cache;
1881 if (cache_info == (Cache) NULL)
1882 return((Quantum *) NULL);
1883 assert(cache_info->signature == MagickSignature);
1884 assert(id < (int) cache_info->number_threads);
1885 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1886 cache_info->nexus_info[id],exception);
1891 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1895 + G e t I m a g e E x t e n t %
1899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1901 % GetImageExtent() returns the extent of the pixels associated corresponding
1902 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1904 % The format of the GetImageExtent() method is:
1906 % MagickSizeType GetImageExtent(const Image *image)
1908 % A description of each parameter follows:
1910 % o image: the image.
1913 MagickExport MagickSizeType GetImageExtent(const Image *image)
1919 id = GetOpenMPThreadId();
1921 assert(image != (Image *) NULL);
1922 assert(image->signature == MagickSignature);
1923 if (image->debug != MagickFalse)
1924 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1925 assert(image->cache != (Cache) NULL);
1926 cache_info=(CacheInfo *) image->cache;
1927 assert(cache_info->signature == MagickSignature);
1928 assert(id < (int) cache_info->number_threads);
1929 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1937 + G e t I m a g e P i x e l C a c h e %
1941 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1943 % GetImagePixelCache() ensures that there is only a single reference to the
1944 % pixel cache to be modified, updating the provided cache pointer to point to
1945 % a clone of the original pixel cache if necessary.
1947 % The format of the GetImagePixelCache method is:
1949 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1950 % ExceptionInfo *exception)
1952 % A description of each parameter follows:
1954 % o image: the image.
1956 % o clone: any value other than MagickFalse clones the cache pixels.
1958 % o exception: return any errors or warnings in this structure.
1962 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1968 Does the image match the pixel cache morphology?
1970 cache_info=(CacheInfo *) image->cache;
1971 if ((image->storage_class != cache_info->storage_class) ||
1972 (image->colorspace != cache_info->colorspace) ||
1973 (image->matte != cache_info->matte) ||
1974 (image->columns != cache_info->columns) ||
1975 (image->rows != cache_info->rows) ||
1976 (image->number_channels != cache_info->number_channels) ||
1977 (image->metacontent_extent != cache_info->metacontent_extent) ||
1978 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1979 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1980 return(MagickFalse);
1984 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1985 ExceptionInfo *exception)
1994 static MagickSizeType
2000 cache_timestamp = 0;
2003 LockSemaphoreInfo(image->semaphore);
2004 if (cpu_throttle == 0)
2010 Set CPU throttle in milleseconds.
2012 cpu_throttle=MagickResourceInfinity;
2013 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2014 if (limit == (char *) NULL)
2015 limit=GetPolicyValue("throttle");
2016 if (limit != (char *) NULL)
2018 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2019 limit=DestroyString(limit);
2022 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2023 MagickDelay(cpu_throttle);
2024 if (time_limit == 0)
2027 Set the exire time in seconds.
2029 time_limit=GetMagickResourceLimit(TimeResource);
2030 cache_timestamp=time((time_t *) NULL);
2032 if ((time_limit != MagickResourceInfinity) &&
2033 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
2034 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2035 assert(image->cache != (Cache) NULL);
2036 cache_info=(CacheInfo *) image->cache;
2037 destroy=MagickFalse;
2038 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2040 LockSemaphoreInfo(cache_info->semaphore);
2041 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2052 clone_image=(*image);
2053 clone_image.semaphore=AllocateSemaphoreInfo();
2054 clone_image.reference_count=1;
2055 clone_image.cache=ClonePixelCache(cache_info);
2056 clone_info=(CacheInfo *) clone_image.cache;
2057 status=OpenPixelCache(&clone_image,IOMode,exception);
2058 if (status != MagickFalse)
2060 if (clone != MagickFalse)
2061 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2062 if (status != MagickFalse)
2064 if (cache_info->mode == ReadMode)
2065 cache_info->nexus_info=(NexusInfo **) NULL;
2067 image->cache=clone_image.cache;
2070 DestroySemaphoreInfo(&clone_image.semaphore);
2072 UnlockSemaphoreInfo(cache_info->semaphore);
2074 if (destroy != MagickFalse)
2075 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2076 if (status != MagickFalse)
2079 Ensure the image matches the pixel cache morphology.
2081 image->taint=MagickTrue;
2082 image->type=UndefinedType;
2083 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2084 status=OpenPixelCache(image,IOMode,exception);
2086 UnlockSemaphoreInfo(image->semaphore);
2087 if (status == MagickFalse)
2088 return((Cache) NULL);
2089 return(image->cache);
2093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2097 % G e t O n e A u t h e n t i c P i x e l %
2101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2103 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2104 % location. The image background color is returned if an error occurs.
2106 % The format of the GetOneAuthenticPixel() method is:
2108 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2109 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2111 % A description of each parameter follows:
2113 % o image: the image.
2115 % o x,y: These values define the location of the pixel to return.
2117 % o pixel: return a pixel at the specified (x,y) location.
2119 % o exception: return any errors or warnings in this structure.
2122 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2123 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2134 assert(image != (Image *) NULL);
2135 assert(image->signature == MagickSignature);
2136 assert(image->cache != (Cache) NULL);
2137 cache_info=(CacheInfo *) image->cache;
2138 assert(cache_info->signature == MagickSignature);
2139 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2140 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2141 (GetOneAuthenticPixelFromHandler) NULL)
2142 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2144 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2145 if (q == (Quantum *) NULL)
2147 pixel[RedPixelChannel]=image->background_color.red;
2148 pixel[GreenPixelChannel]=image->background_color.green;
2149 pixel[BluePixelChannel]=image->background_color.blue;
2150 pixel[AlphaPixelChannel]=image->background_color.alpha;
2151 return(MagickFalse);
2153 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2158 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2159 pixel[channel]=q[i];
2165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2169 + 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 %
2173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2175 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2176 % location. The image background color is returned if an error occurs.
2178 % The format of the GetOneAuthenticPixelFromCache() method is:
2180 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2181 % const ssize_t x,const ssize_t y,Quantum *pixel,
2182 % ExceptionInfo *exception)
2184 % A description of each parameter follows:
2186 % o image: the image.
2188 % o x,y: These values define the location of the pixel to return.
2190 % o pixel: return a pixel at the specified (x,y) location.
2192 % o exception: return any errors or warnings in this structure.
2195 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2196 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2202 id = GetOpenMPThreadId();
2210 assert(image != (const Image *) NULL);
2211 assert(image->signature == MagickSignature);
2212 assert(image->cache != (Cache) NULL);
2213 cache_info=(CacheInfo *) image->cache;
2214 assert(cache_info->signature == MagickSignature);
2215 assert(id < (int) cache_info->number_threads);
2216 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2217 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2219 if (q == (Quantum *) NULL)
2221 pixel[RedPixelChannel]=image->background_color.red;
2222 pixel[GreenPixelChannel]=image->background_color.green;
2223 pixel[BluePixelChannel]=image->background_color.blue;
2224 pixel[AlphaPixelChannel]=image->background_color.alpha;
2225 return(MagickFalse);
2227 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2232 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2233 pixel[channel]=q[i];
2239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243 % G e t O n e V i r t u a l M a g i c k P i x e l %
2247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2249 % GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2250 % location. The image background color is returned if an error occurs. If
2251 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2253 % The format of the GetOneVirtualMagickPixel() method is:
2255 % MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2256 % const ssize_t x,const ssize_t y,PixelInfo *pixel,
2257 % ExceptionInfo exception)
2259 % A description of each parameter follows:
2261 % o image: the image.
2263 % o x,y: these values define the location of the pixel to return.
2265 % o pixel: return a pixel at the specified (x,y) location.
2267 % o exception: return any errors or warnings in this structure.
2270 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2271 const ssize_t x,const ssize_t y,PixelInfo *pixel,
2272 ExceptionInfo *exception)
2278 id = GetOpenMPThreadId();
2280 register const Quantum
2283 assert(image != (const Image *) NULL);
2284 assert(image->signature == MagickSignature);
2285 assert(image->cache != (Cache) NULL);
2286 cache_info=(CacheInfo *) image->cache;
2287 assert(cache_info->signature == MagickSignature);
2288 assert(id < (int) cache_info->number_threads);
2289 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2290 1UL,1UL,cache_info->nexus_info[id],exception);
2291 GetPixelInfo(image,pixel);
2292 if (p == (const Quantum *) NULL)
2293 return(MagickFalse);
2294 SetPixelInfo(image,p,pixel);
2299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2303 % G e t O n e V i r t u a l M e t h o d P i x e l %
2307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2309 % GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2310 % location as defined by specified pixel method. The image background color
2311 % is returned if an error occurs. If you plan to modify the pixel, use
2312 % GetOneAuthenticPixel() instead.
2314 % The format of the GetOneVirtualMethodPixel() method is:
2316 % MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2317 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2318 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2320 % A description of each parameter follows:
2322 % o image: the image.
2324 % o virtual_pixel_method: the virtual pixel method.
2326 % o x,y: These values define the location of the pixel to return.
2328 % o pixel: return a pixel at the specified (x,y) location.
2330 % o exception: return any errors or warnings in this structure.
2333 MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2334 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2335 Quantum *pixel,ExceptionInfo *exception)
2341 id = GetOpenMPThreadId();
2349 assert(image != (const Image *) NULL);
2350 assert(image->signature == MagickSignature);
2351 assert(image->cache != (Cache) NULL);
2352 cache_info=(CacheInfo *) image->cache;
2353 assert(cache_info->signature == MagickSignature);
2354 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2355 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2356 (GetOneVirtualPixelFromHandler) NULL)
2357 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2358 virtual_pixel_method,x,y,pixel,exception));
2359 assert(id < (int) cache_info->number_threads);
2360 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2361 cache_info->nexus_info[id],exception);
2362 if (p == (const Quantum *) NULL)
2364 pixel[RedPixelChannel]=image->background_color.red;
2365 pixel[GreenPixelChannel]=image->background_color.green;
2366 pixel[BluePixelChannel]=image->background_color.blue;
2367 pixel[AlphaPixelChannel]=image->background_color.alpha;
2368 return(MagickFalse);
2370 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2375 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2376 pixel[channel]=p[i];
2382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2386 % G e t O n e V i r t u a l P i x e l %
2390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2392 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2393 % (x,y) location. The image background color is returned if an error occurs.
2394 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2396 % The format of the GetOneVirtualPixel() method is:
2398 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2399 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2401 % A description of each parameter follows:
2403 % o image: the image.
2405 % o x,y: These values define the location of the pixel to return.
2407 % o pixel: return a pixel at the specified (x,y) location.
2409 % o exception: return any errors or warnings in this structure.
2412 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2413 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2419 id = GetOpenMPThreadId();
2427 assert(image != (const Image *) NULL);
2428 assert(image->signature == MagickSignature);
2429 assert(image->cache != (Cache) NULL);
2430 cache_info=(CacheInfo *) image->cache;
2431 assert(cache_info->signature == MagickSignature);
2432 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2433 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2434 (GetOneVirtualPixelFromHandler) NULL)
2435 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2436 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2437 assert(id < (int) cache_info->number_threads);
2438 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2439 1UL,1UL,cache_info->nexus_info[id],exception);
2440 if (p == (const Quantum *) NULL)
2442 pixel[RedPixelChannel]=image->background_color.red;
2443 pixel[GreenPixelChannel]=image->background_color.green;
2444 pixel[BluePixelChannel]=image->background_color.blue;
2445 pixel[AlphaPixelChannel]=image->background_color.alpha;
2446 return(MagickFalse);
2448 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2453 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2454 pixel[channel]=p[i];
2460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2464 + 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 %
2468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2470 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2471 % specified (x,y) location. The image background color is returned if an
2474 % The format of the GetOneVirtualPixelFromCache() method is:
2476 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2477 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2478 % Quantum *pixel,ExceptionInfo *exception)
2480 % A description of each parameter follows:
2482 % o image: the image.
2484 % o virtual_pixel_method: the virtual pixel method.
2486 % o x,y: These values define the location of the pixel to return.
2488 % o pixel: return a pixel at the specified (x,y) location.
2490 % o exception: return any errors or warnings in this structure.
2493 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2494 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2495 Quantum *pixel,ExceptionInfo *exception)
2501 id = GetOpenMPThreadId();
2509 assert(image != (const Image *) NULL);
2510 assert(image->signature == MagickSignature);
2511 assert(image->cache != (Cache) NULL);
2512 cache_info=(CacheInfo *) image->cache;
2513 assert(cache_info->signature == MagickSignature);
2514 assert(id < (int) cache_info->number_threads);
2515 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2516 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2517 cache_info->nexus_info[id],exception);
2518 if (p == (const Quantum *) NULL)
2520 pixel[RedPixelChannel]=image->background_color.red;
2521 pixel[GreenPixelChannel]=image->background_color.green;
2522 pixel[BluePixelChannel]=image->background_color.blue;
2523 pixel[AlphaPixelChannel]=image->background_color.alpha;
2524 return(MagickFalse);
2526 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2531 channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
2532 pixel[channel]=p[i];
2538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2542 + G e t P i x e l C a c h e C o l o r s p a c e %
2546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2548 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2550 % The format of the GetPixelCacheColorspace() method is:
2552 % Colorspace GetPixelCacheColorspace(Cache cache)
2554 % A description of each parameter follows:
2556 % o cache: the pixel cache.
2559 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2564 assert(cache != (Cache) NULL);
2565 cache_info=(CacheInfo *) cache;
2566 assert(cache_info->signature == MagickSignature);
2567 if (cache_info->debug != MagickFalse)
2568 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2569 cache_info->filename);
2570 return(cache_info->colorspace);
2574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2578 + G e t P i x e l C a c h e M e t h o d s %
2582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2584 % GetPixelCacheMethods() initializes the CacheMethods structure.
2586 % The format of the GetPixelCacheMethods() method is:
2588 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2590 % A description of each parameter follows:
2592 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2595 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2597 assert(cache_methods != (CacheMethods *) NULL);
2598 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2599 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2600 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2601 cache_methods->get_virtual_metacontent_from_handler=
2602 GetVirtualMetacontentFromCache;
2603 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2604 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2605 cache_methods->get_authentic_metacontent_from_handler=
2606 GetAuthenticMetacontentFromCache;
2607 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2608 cache_methods->get_one_authentic_pixel_from_handler=
2609 GetOneAuthenticPixelFromCache;
2610 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2611 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2612 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2620 + G e t P i x e l C a c h e N e x u s E x t e n t %
2624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2626 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2627 % corresponding with the last call to SetPixelCacheNexusPixels() or
2628 % GetPixelCacheNexusPixels().
2630 % The format of the GetPixelCacheNexusExtent() method is:
2632 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2633 % NexusInfo *nexus_info)
2635 % A description of each parameter follows:
2637 % o nexus_info: the nexus info.
2640 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2641 NexusInfo *nexus_info)
2649 assert(cache != NULL);
2650 cache_info=(CacheInfo *) cache;
2651 assert(cache_info->signature == MagickSignature);
2652 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2654 return((MagickSizeType) cache_info->columns*cache_info->rows);
2659 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2663 + 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 %
2667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2669 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2672 % The format of the GetPixelCacheNexusMetacontent() method is:
2674 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2675 % NexusInfo *nexus_info)
2677 % A description of each parameter follows:
2679 % o cache: the pixel cache.
2681 % o nexus_info: the cache nexus to return the meta-content.
2684 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2685 NexusInfo *nexus_info)
2690 assert(cache != NULL);
2691 cache_info=(CacheInfo *) cache;
2692 assert(cache_info->signature == MagickSignature);
2693 if (cache_info->storage_class == UndefinedClass)
2694 return((void *) NULL);
2695 return(nexus_info->metacontent);
2699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2703 + G e t P i x e l C a c h e N e x u s P i x e l s %
2707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2709 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2712 % The format of the GetPixelCacheNexusPixels() method is:
2714 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2715 % NexusInfo *nexus_info)
2717 % A description of each parameter follows:
2719 % o cache: the pixel cache.
2721 % o nexus_info: the cache nexus to return the pixels.
2724 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2725 NexusInfo *nexus_info)
2730 assert(cache != NULL);
2731 cache_info=(CacheInfo *) cache;
2732 assert(cache_info->signature == MagickSignature);
2733 if (cache_info->storage_class == UndefinedClass)
2734 return((Quantum *) NULL);
2735 return(nexus_info->pixels);
2739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2743 + G e t P i x e l C a c h e P i x e l s %
2747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749 % GetPixelCachePixels() returns the pixels associated with the specified image.
2751 % The format of the GetPixelCachePixels() method is:
2753 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2754 % ExceptionInfo *exception)
2756 % A description of each parameter follows:
2758 % o image: the image.
2760 % o length: the pixel cache length.
2762 % o exception: return any errors or warnings in this structure.
2765 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2766 ExceptionInfo *exception)
2771 assert(image != (const Image *) NULL);
2772 assert(image->signature == MagickSignature);
2773 assert(image->cache != (Cache) NULL);
2774 assert(length != (MagickSizeType *) NULL);
2775 assert(exception != (ExceptionInfo *) NULL);
2776 assert(exception->signature == MagickSignature);
2777 cache_info=(CacheInfo *) image->cache;
2778 assert(cache_info->signature == MagickSignature);
2780 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2781 return((void *) NULL);
2782 *length=cache_info->length;
2783 return((void *) cache_info->pixels);
2787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2791 + 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 %
2795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2797 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2799 % The format of the GetPixelCacheStorageClass() method is:
2801 % ClassType GetPixelCacheStorageClass(Cache cache)
2803 % A description of each parameter follows:
2805 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2807 % o cache: the pixel cache.
2810 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2815 assert(cache != (Cache) NULL);
2816 cache_info=(CacheInfo *) cache;
2817 assert(cache_info->signature == MagickSignature);
2818 if (cache_info->debug != MagickFalse)
2819 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2820 cache_info->filename);
2821 return(cache_info->storage_class);
2825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2829 + G e t P i x e l C a c h e T i l e S i z e %
2833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2835 % GetPixelCacheTileSize() returns the pixel cache tile size.
2837 % The format of the GetPixelCacheTileSize() method is:
2839 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2842 % A description of each parameter follows:
2844 % o image: the image.
2846 % o width: the optimize cache tile width in pixels.
2848 % o height: the optimize cache tile height in pixels.
2851 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2857 assert(image != (Image *) NULL);
2858 assert(image->signature == MagickSignature);
2859 if (image->debug != MagickFalse)
2860 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2861 cache_info=(CacheInfo *) image->cache;
2862 assert(cache_info->signature == MagickSignature);
2863 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2864 if (GetPixelCacheType(image) == DiskCache)
2865 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2874 + G e t P i x e l C a c h e T y p e %
2878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2880 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2882 % The format of the GetPixelCacheType() method is:
2884 % CacheType GetPixelCacheType(const Image *image)
2886 % A description of each parameter follows:
2888 % o image: the image.
2891 MagickPrivate CacheType GetPixelCacheType(const Image *image)
2896 assert(image != (Image *) NULL);
2897 assert(image->signature == MagickSignature);
2898 assert(image->cache != (Cache) NULL);
2899 cache_info=(CacheInfo *) image->cache;
2900 assert(cache_info->signature == MagickSignature);
2901 return(cache_info->type);
2905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2909 + 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 %
2913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2915 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2916 % pixel cache. A virtual pixel is any pixel access that is outside the
2917 % boundaries of the image cache.
2919 % The format of the GetPixelCacheVirtualMethod() method is:
2921 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2923 % A description of each parameter follows:
2925 % o image: the image.
2928 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2933 assert(image != (Image *) NULL);
2934 assert(image->signature == MagickSignature);
2935 assert(image->cache != (Cache) NULL);
2936 cache_info=(CacheInfo *) image->cache;
2937 assert(cache_info->signature == MagickSignature);
2938 return(cache_info->virtual_pixel_method);
2942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2946 + 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 %
2950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2952 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2953 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2955 % The format of the GetVirtualMetacontentFromCache() method is:
2957 % void *GetVirtualMetacontentFromCache(const Image *image)
2959 % A description of each parameter follows:
2961 % o image: the image.
2964 static const void *GetVirtualMetacontentFromCache(const Image *image)
2970 id = GetOpenMPThreadId();
2975 assert(image != (const Image *) NULL);
2976 assert(image->signature == MagickSignature);
2977 assert(image->cache != (Cache) NULL);
2978 cache_info=(CacheInfo *) image->cache;
2979 assert(cache_info->signature == MagickSignature);
2980 assert(id < (int) cache_info->number_threads);
2981 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2982 cache_info->nexus_info[id]);
2983 return(metacontent);
2987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2991 + 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 %
2995 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2997 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
3000 % The format of the GetVirtualMetacontentFromNexus() method is:
3002 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
3003 % NexusInfo *nexus_info)
3005 % A description of each parameter follows:
3007 % o cache: the pixel cache.
3009 % o nexus_info: the cache nexus to return the meta-content.
3012 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
3013 NexusInfo *nexus_info)
3018 assert(cache != (Cache) NULL);
3019 cache_info=(CacheInfo *) cache;
3020 assert(cache_info->signature == MagickSignature);
3021 if (cache_info->storage_class == UndefinedClass)
3022 return((void *) NULL);
3023 return(nexus_info->metacontent);
3027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3031 % G e t V i r t u a l M e t a c o n t e n t %
3035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3037 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
3038 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3039 % returned if the meta-content are not available.
3041 % The format of the GetVirtualMetacontent() method is:
3043 % const void *GetVirtualMetacontent(const Image *image)
3045 % A description of each parameter follows:
3047 % o image: the image.
3050 MagickExport const void *GetVirtualMetacontent(const Image *image)
3056 id = GetOpenMPThreadId();
3061 assert(image != (const Image *) NULL);
3062 assert(image->signature == MagickSignature);
3063 assert(image->cache != (Cache) NULL);
3064 cache_info=(CacheInfo *) image->cache;
3065 assert(cache_info->signature == MagickSignature);
3066 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3067 (GetVirtualMetacontentFromHandler) NULL)
3069 metacontent=cache_info->methods.
3070 get_virtual_metacontent_from_handler(image);
3071 return(metacontent);
3073 assert(id < (int) cache_info->number_threads);
3074 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3075 cache_info->nexus_info[id]);
3076 return(metacontent);
3080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3084 + 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 %
3088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3090 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3091 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3092 % is returned if the pixels are transferred, otherwise a NULL is returned.
3094 % The format of the GetVirtualPixelsFromNexus() method is:
3096 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
3097 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3098 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
3099 % ExceptionInfo *exception)
3101 % A description of each parameter follows:
3103 % o image: the image.
3105 % o virtual_pixel_method: the virtual pixel method.
3107 % o x,y,columns,rows: These values define the perimeter of a region of
3110 % o nexus_info: the cache nexus to acquire.
3112 % o exception: return any errors or warnings in this structure.
3119 0, 48, 12, 60, 3, 51, 15, 63,
3120 32, 16, 44, 28, 35, 19, 47, 31,
3121 8, 56, 4, 52, 11, 59, 7, 55,
3122 40, 24, 36, 20, 43, 27, 39, 23,
3123 2, 50, 14, 62, 1, 49, 13, 61,
3124 34, 18, 46, 30, 33, 17, 45, 29,
3125 10, 58, 6, 54, 9, 57, 5, 53,
3126 42, 26, 38, 22, 41, 25, 37, 21
3129 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3134 index=x+DitherMatrix[x & 0x07]-32L;
3137 if (index >= (ssize_t) columns)
3138 return((ssize_t) columns-1L);
3142 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3147 index=y+DitherMatrix[y & 0x07]-32L;
3150 if (index >= (ssize_t) rows)
3151 return((ssize_t) rows-1L);
3155 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3159 if (x >= (ssize_t) columns)
3160 return((ssize_t) (columns-1));
3164 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3168 if (y >= (ssize_t) rows)
3169 return((ssize_t) (rows-1));
3173 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3175 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3178 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3180 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3183 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3184 const size_t extent)
3190 Compute the remainder of dividing offset by extent. It returns not only
3191 the quotient (tile the offset falls in) but also the positive remainer
3192 within that tile such that 0 <= remainder < extent. This method is
3193 essentially a ldiv() using a floored modulo division rather than the
3194 normal default truncated modulo division.
3196 modulo.quotient=offset/(ssize_t) extent;
3199 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3203 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3204 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3205 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3206 ExceptionInfo *exception)
3223 virtual_pixel[MaxPixelChannels];
3228 register const Quantum
3241 register unsigned char
3248 *virtual_metacontent;
3253 assert(image != (const Image *) NULL);
3254 assert(image->signature == MagickSignature);
3255 assert(image->cache != (Cache) NULL);
3256 cache_info=(CacheInfo *) image->cache;
3257 assert(cache_info->signature == MagickSignature);
3258 if (cache_info->type == UndefinedCache)
3259 return((const Quantum *) NULL);
3262 region.width=columns;
3264 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3265 if (pixels == (Quantum *) NULL)
3266 return((const Quantum *) NULL);
3268 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3269 nexus_info->region.x;
3270 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3271 nexus_info->region.width-1L;
3272 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3273 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3274 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3275 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3281 Pixel request is inside cache extents.
3283 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3285 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3286 if (status == MagickFalse)
3287 return((const Quantum *) NULL);
3288 if (cache_info->metacontent_extent != 0)
3290 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3291 if (status == MagickFalse)
3292 return((const Quantum *) NULL);
3297 Pixel request is outside cache extents.
3299 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3300 virtual_nexus=AcquirePixelCacheNexus(1);
3301 if (virtual_nexus == (NexusInfo **) NULL)
3303 if (virtual_nexus != (NexusInfo **) NULL)
3304 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3305 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3306 "UnableToGetCacheNexus","`%s'",image->filename);
3307 return((const Quantum *) NULL);
3309 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3310 sizeof(*virtual_pixel));
3311 virtual_metacontent=(void *) NULL;
3312 switch (virtual_pixel_method)
3314 case BackgroundVirtualPixelMethod:
3315 case BlackVirtualPixelMethod:
3316 case GrayVirtualPixelMethod:
3317 case TransparentVirtualPixelMethod:
3318 case MaskVirtualPixelMethod:
3319 case WhiteVirtualPixelMethod:
3320 case EdgeVirtualPixelMethod:
3321 case CheckerTileVirtualPixelMethod:
3322 case HorizontalTileVirtualPixelMethod:
3323 case VerticalTileVirtualPixelMethod:
3325 if (cache_info->metacontent_extent != 0)
3328 Acquire a metacontent buffer.
3330 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3331 cache_info->metacontent_extent);
3332 if (virtual_metacontent == (void *) NULL)
3334 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3335 (void) ThrowMagickException(exception,GetMagickModule(),
3336 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3337 return((const Quantum *) NULL);
3339 (void) ResetMagickMemory(virtual_metacontent,0,
3340 cache_info->metacontent_extent);
3342 switch (virtual_pixel_method)
3344 case BlackVirtualPixelMethod:
3346 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3347 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3348 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3351 case GrayVirtualPixelMethod:
3353 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3354 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3356 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3359 case TransparentVirtualPixelMethod:
3361 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3362 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3363 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3366 case MaskVirtualPixelMethod:
3367 case WhiteVirtualPixelMethod:
3369 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3370 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3371 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3376 SetPixelRed(image,image->background_color.red,virtual_pixel);
3377 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3378 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
3379 if (image->colorspace == CMYKColorspace)
3380 SetPixelBlack(image,image->background_color.black,virtual_pixel);
3381 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3390 for (v=0; v < (ssize_t) rows; v++)
3392 for (u=0; u < (ssize_t) columns; u+=length)
3394 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3395 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3396 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3404 Transfer a single pixel.
3406 length=(MagickSizeType) 1;
3407 switch (virtual_pixel_method)
3411 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3412 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3413 1UL,1UL,*virtual_nexus,exception);
3414 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3417 case RandomVirtualPixelMethod:
3419 if (cache_info->random_info == (RandomInfo *) NULL)
3420 cache_info->random_info=AcquireRandomInfo();
3421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3422 RandomX(cache_info->random_info,cache_info->columns),
3423 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3424 *virtual_nexus,exception);
3425 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3428 case DitherVirtualPixelMethod:
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3431 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3432 1UL,1UL,*virtual_nexus,exception);
3433 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3436 case TileVirtualPixelMethod:
3438 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3439 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3440 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3441 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3443 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3446 case MirrorVirtualPixelMethod:
3448 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3449 if ((x_modulo.quotient & 0x01) == 1L)
3450 x_modulo.remainder=(ssize_t) cache_info->columns-
3451 x_modulo.remainder-1L;
3452 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3453 if ((y_modulo.quotient & 0x01) == 1L)
3454 y_modulo.remainder=(ssize_t) cache_info->rows-
3455 y_modulo.remainder-1L;
3456 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3457 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3459 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3462 case HorizontalTileEdgeVirtualPixelMethod:
3464 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3465 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3466 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3467 *virtual_nexus,exception);
3468 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3471 case VerticalTileEdgeVirtualPixelMethod:
3473 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3474 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3475 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3476 *virtual_nexus,exception);
3477 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3480 case BackgroundVirtualPixelMethod:
3481 case BlackVirtualPixelMethod:
3482 case GrayVirtualPixelMethod:
3483 case TransparentVirtualPixelMethod:
3484 case MaskVirtualPixelMethod:
3485 case WhiteVirtualPixelMethod:
3488 r=virtual_metacontent;
3491 case EdgeVirtualPixelMethod:
3492 case CheckerTileVirtualPixelMethod:
3494 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3495 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3496 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3499 r=virtual_metacontent;
3502 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3503 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3505 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3508 case HorizontalTileVirtualPixelMethod:
3510 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3513 r=virtual_metacontent;
3516 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3517 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3518 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3519 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3521 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3524 case VerticalTileVirtualPixelMethod:
3526 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3529 r=virtual_metacontent;
3532 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3533 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3534 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3535 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3537 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3541 if (p == (const Quantum *) NULL)
3543 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3545 q+=cache_info->number_channels;
3546 if ((s != (void *) NULL) && (r != (const void *) NULL))
3548 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3549 s+=cache_info->metacontent_extent;
3554 Transfer a run of pixels.
3556 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3557 length,1UL,*virtual_nexus,exception);
3558 if (p == (const Quantum *) NULL)
3560 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3561 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3562 q+=length*cache_info->number_channels;
3563 if ((r != (void *) NULL) && (s != (const void *) NULL))
3565 (void) memcpy(s,r,(size_t) length);
3566 s+=length*cache_info->metacontent_extent;
3573 if (virtual_metacontent != (void *) NULL)
3574 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3575 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3584 + G e t V i r t u a l P i x e l C a c h e %
3588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3590 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3591 % cache as defined by the geometry parameters. A pointer to the pixels
3592 % is returned if the pixels are transferred, otherwise a NULL is returned.
3594 % The format of the GetVirtualPixelCache() method is:
3596 % const Quantum *GetVirtualPixelCache(const Image *image,
3597 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3598 % const ssize_t y,const size_t columns,const size_t rows,
3599 % ExceptionInfo *exception)
3601 % A description of each parameter follows:
3603 % o image: the image.
3605 % o virtual_pixel_method: the virtual pixel method.
3607 % o x,y,columns,rows: These values define the perimeter of a region of
3610 % o exception: return any errors or warnings in this structure.
3613 static const Quantum *GetVirtualPixelCache(const Image *image,
3614 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3615 const size_t columns,const size_t rows,ExceptionInfo *exception)
3621 id = GetOpenMPThreadId();
3626 assert(image != (const Image *) NULL);
3627 assert(image->signature == MagickSignature);
3628 assert(image->cache != (Cache) NULL);
3629 cache_info=(CacheInfo *) image->cache;
3630 assert(cache_info->signature == MagickSignature);
3631 assert(id < (int) cache_info->number_threads);
3632 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3633 cache_info->nexus_info[id],exception);
3638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3642 % G e t V i r t u a l P i x e l Q u e u e %
3646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3648 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3649 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3651 % The format of the GetVirtualPixelQueue() method is:
3653 % const Quantum *GetVirtualPixelQueue(const Image image)
3655 % A description of each parameter follows:
3657 % o image: the image.
3660 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3666 id = GetOpenMPThreadId();
3668 assert(image != (const Image *) NULL);
3669 assert(image->signature == MagickSignature);
3670 assert(image->cache != (Cache) NULL);
3671 cache_info=(CacheInfo *) image->cache;
3672 assert(cache_info->signature == MagickSignature);
3673 if (cache_info->methods.get_virtual_pixels_handler !=
3674 (GetVirtualPixelsHandler) NULL)
3675 return(cache_info->methods.get_virtual_pixels_handler(image));
3676 assert(id < (int) cache_info->number_threads);
3677 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3685 % G e t V i r t u a l P i x e l s %
3689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3691 % GetVirtualPixels() returns an immutable pixel region. If the
3692 % region is successfully accessed, a pointer to it is returned, otherwise
3693 % NULL is returned. The returned pointer may point to a temporary working
3694 % copy of the pixels or it may point to the original pixels in memory.
3695 % Performance is maximized if the selected region is part of one row, or one
3696 % or more full rows, since there is opportunity to access the pixels in-place
3697 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3698 % returned pointer must *never* be deallocated by the user.
3700 % Pixels accessed via the returned pointer represent a simple array of type
3701 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3702 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3703 % access the meta-content (of type void) corresponding to the the
3706 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3708 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3709 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3710 % GetCacheViewAuthenticPixels() instead.
3712 % The format of the GetVirtualPixels() method is:
3714 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3715 % const ssize_t y,const size_t columns,const size_t rows,
3716 % ExceptionInfo *exception)
3718 % A description of each parameter follows:
3720 % o image: the image.
3722 % o x,y,columns,rows: These values define the perimeter of a region of
3725 % o exception: return any errors or warnings in this structure.
3728 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3729 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3730 ExceptionInfo *exception)
3736 id = GetOpenMPThreadId();
3741 assert(image != (const Image *) NULL);
3742 assert(image->signature == MagickSignature);
3743 assert(image->cache != (Cache) NULL);
3744 cache_info=(CacheInfo *) image->cache;
3745 assert(cache_info->signature == MagickSignature);
3746 if (cache_info->methods.get_virtual_pixel_handler !=
3747 (GetVirtualPixelHandler) NULL)
3748 return(cache_info->methods.get_virtual_pixel_handler(image,
3749 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3750 assert(id < (int) cache_info->number_threads);
3751 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3752 columns,rows,cache_info->nexus_info[id],exception);
3757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3761 + 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 %
3765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3767 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3768 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3770 % The format of the GetVirtualPixelsCache() method is:
3772 % Quantum *GetVirtualPixelsCache(const Image *image)
3774 % A description of each parameter follows:
3776 % o image: the image.
3779 static const Quantum *GetVirtualPixelsCache(const Image *image)
3785 id = GetOpenMPThreadId();
3787 assert(image != (const Image *) NULL);
3788 assert(image->signature == MagickSignature);
3789 assert(image->cache != (Cache) NULL);
3790 cache_info=(CacheInfo *) image->cache;
3791 assert(cache_info->signature == MagickSignature);
3792 assert(id < (int) cache_info->number_threads);
3793 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3801 + G e t V i r t u a l P i x e l s N e x u s %
3805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3807 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3810 % The format of the GetVirtualPixelsNexus() method is:
3812 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3813 % NexusInfo *nexus_info)
3815 % A description of each parameter follows:
3817 % o cache: the pixel cache.
3819 % o nexus_info: the cache nexus to return the colormap pixels.
3822 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3823 NexusInfo *nexus_info)
3828 assert(cache != (Cache) NULL);
3829 cache_info=(CacheInfo *) cache;
3830 assert(cache_info->signature == MagickSignature);
3831 if (cache_info->storage_class == UndefinedClass)
3832 return((Quantum *) NULL);
3833 return((const Quantum *) nexus_info->pixels);
3837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3841 + M a s k P i x e l C a c h e N e x u s %
3845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3847 % MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3848 % The method returns MagickTrue if the pixel region is masked, otherwise
3851 % The format of the MaskPixelCacheNexus() method is:
3853 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3854 % NexusInfo *nexus_info,ExceptionInfo *exception)
3856 % A description of each parameter follows:
3858 % o image: the image.
3860 % o nexus_info: the cache nexus to clip.
3862 % o exception: return any errors or warnings in this structure.
3866 static inline void MagickPixelCompositeMask(const PixelInfo *p,
3867 const MagickRealType alpha,const PixelInfo *q,
3868 const MagickRealType beta,PixelInfo *composite)
3873 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
3878 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3879 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3880 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3881 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3882 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3883 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3884 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
3887 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3888 ExceptionInfo *exception)
3904 register const Quantum
3917 if (image->debug != MagickFalse)
3918 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3919 if (image->mask == (Image *) NULL)
3920 return(MagickFalse);
3921 cache_info=(CacheInfo *) image->cache;
3922 if (cache_info == (Cache) NULL)
3923 return(MagickFalse);
3924 image_nexus=AcquirePixelCacheNexus(1);
3925 clip_nexus=AcquirePixelCacheNexus(1);
3926 if ((image_nexus == (NexusInfo **) NULL) ||
3927 (clip_nexus == (NexusInfo **) NULL))
3928 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3929 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3930 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3931 nexus_info->region.height,image_nexus[0],exception);
3932 q=nexus_info->pixels;
3933 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3934 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3935 nexus_info->region.height,clip_nexus[0],&image->exception);
3936 GetPixelInfo(image,&alpha);
3937 GetPixelInfo(image,&beta);
3938 number_pixels=(MagickSizeType) nexus_info->region.width*
3939 nexus_info->region.height;
3940 for (i=0; i < (ssize_t) number_pixels; i++)
3942 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
3944 SetPixelInfo(image,p,&alpha);
3945 SetPixelInfo(image,q,&beta);
3946 MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3947 &alpha,alpha.alpha,&beta);
3948 SetPixelRed(image,ClampToQuantum(beta.red),q);
3949 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3950 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3951 if (cache_info->colorspace == CMYKColorspace)
3952 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3953 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
3958 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3959 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3960 if (i < (ssize_t) number_pixels)
3961 return(MagickFalse);
3966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3970 + O p e n P i x e l C a c h e %
3974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3976 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3977 % dimensions, allocating space for the image pixels and optionally the
3978 % metacontent, and memory mapping the cache if it is disk based. The cache
3979 % nexus array is initialized as well.
3981 % The format of the OpenPixelCache() method is:
3983 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3984 % ExceptionInfo *exception)
3986 % A description of each parameter follows:
3988 % o image: the image.
3990 % o mode: ReadMode, WriteMode, or IOMode.
3992 % o exception: return any errors or warnings in this structure.
3996 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3998 cache_info->mapped=MagickFalse;
3999 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
4000 cache_info->length);
4001 if (cache_info->pixels == (Quantum *) NULL)
4003 cache_info->mapped=MagickTrue;
4004 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4005 cache_info->length);
4009 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4019 cache_info=(CacheInfo *) image->cache;
4020 if (image->debug != MagickFalse)
4023 format[MaxTextExtent],
4024 message[MaxTextExtent];
4026 (void) FormatMagickSize(length,MagickFalse,format);
4027 (void) FormatLocaleString(message,MaxTextExtent,
4028 "extend %s (%s[%d], disk, %s)",cache_info->filename,
4029 cache_info->cache_filename,cache_info->file,format);
4030 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4032 if (length != (MagickSizeType) ((MagickOffsetType) length))
4033 return(MagickFalse);
4034 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
4036 return(MagickFalse);
4037 if ((MagickSizeType) extent >= length)
4039 offset=(MagickOffsetType) length-1;
4040 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4041 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4044 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4045 ExceptionInfo *exception)
4052 format[MaxTextExtent],
4053 message[MaxTextExtent];
4066 assert(image != (const Image *) NULL);
4067 assert(image->signature == MagickSignature);
4068 assert(image->cache != (Cache) NULL);
4069 if (image->debug != MagickFalse)
4070 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4071 if ((image->columns == 0) || (image->rows == 0))
4072 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4073 cache_info=(CacheInfo *) image->cache;
4074 assert(cache_info->signature == MagickSignature);
4075 source_info=(*cache_info);
4076 source_info.file=(-1);
4077 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4078 image->filename,(double) GetImageIndexInList(image));
4079 cache_info->storage_class=image->storage_class;
4080 cache_info->colorspace=image->colorspace;
4081 cache_info->matte=image->matte;
4082 cache_info->rows=image->rows;
4083 cache_info->columns=image->columns;
4084 InitializePixelChannelMap(image);
4085 cache_info->number_channels=GetPixelChannels(image);
4086 cache_info->metacontent_extent=image->metacontent_extent;
4087 cache_info->mode=mode;
4088 if (image->ping != MagickFalse)
4090 cache_info->type=PingCache;
4091 cache_info->pixels=(Quantum *) NULL;
4092 cache_info->metacontent=(void *) NULL;
4093 cache_info->length=0;
4096 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4097 packet_size=cache_info->number_channels*sizeof(Quantum);
4098 if (image->metacontent_extent != 0)
4099 packet_size+=cache_info->metacontent_extent;
4100 length=number_pixels*packet_size;
4101 columns=(size_t) (length/cache_info->rows/packet_size);
4102 if (cache_info->columns != columns)
4103 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4105 cache_info->length=length;
4106 if ((cache_info->type != UndefinedCache) &&
4107 (cache_info->columns <= source_info.columns) &&
4108 (cache_info->rows <= source_info.rows) &&
4109 (cache_info->number_channels <= source_info.number_channels) &&
4110 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4113 Inline pixel cache clone optimization.
4115 if ((cache_info->columns == source_info.columns) &&
4116 (cache_info->rows == source_info.rows) &&
4117 (cache_info->number_channels == source_info.number_channels) &&
4118 (cache_info->metacontent_extent == source_info.metacontent_extent))
4120 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4122 status=AcquireMagickResource(AreaResource,cache_info->length);
4123 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4124 cache_info->metacontent_extent);
4125 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4127 status=AcquireMagickResource(MemoryResource,cache_info->length);
4128 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4129 (cache_info->type == MemoryCache))
4131 AllocatePixelCachePixels(cache_info);
4132 if (cache_info->pixels == (Quantum *) NULL)
4133 cache_info->pixels=source_info.pixels;
4137 Create memory pixel cache.
4140 if (image->debug != MagickFalse)
4142 (void) FormatMagickSize(cache_info->length,MagickTrue,
4144 (void) FormatLocaleString(message,MaxTextExtent,
4145 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4146 cache_info->filename,cache_info->mapped != MagickFalse ?
4147 "anonymous" : "heap",(double) cache_info->columns,(double)
4148 cache_info->rows,(double) cache_info->number_channels,
4150 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4153 cache_info->type=MemoryCache;
4154 cache_info->metacontent=(void *) NULL;
4155 if (cache_info->metacontent_extent != 0)
4156 cache_info->metacontent=(void *) (cache_info->pixels+
4157 number_pixels*cache_info->number_channels);
4158 if (source_info.storage_class != UndefinedClass)
4160 status=ClonePixelCachePixels(cache_info,&source_info,
4162 RelinquishPixelCachePixels(&source_info);
4167 RelinquishMagickResource(MemoryResource,cache_info->length);
4170 Create pixel cache on disk.
4172 status=AcquireMagickResource(DiskResource,cache_info->length);
4173 if (status == MagickFalse)
4175 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4176 "CacheResourcesExhausted","`%s'",image->filename);
4177 return(MagickFalse);
4179 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4181 RelinquishMagickResource(DiskResource,cache_info->length);
4182 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4184 return(MagickFalse);
4186 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4187 cache_info->length);
4188 if (status == MagickFalse)
4190 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4192 return(MagickFalse);
4194 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4195 cache_info->metacontent_extent);
4196 status=AcquireMagickResource(AreaResource,cache_info->length);
4197 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4198 cache_info->type=DiskCache;
4201 status=AcquireMagickResource(MapResource,cache_info->length);
4202 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4203 (cache_info->type != MemoryCache))
4204 cache_info->type=DiskCache;
4207 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4208 cache_info->offset,(size_t) cache_info->length);
4209 if (cache_info->pixels == (Quantum *) NULL)
4211 cache_info->type=DiskCache;
4212 cache_info->pixels=source_info.pixels;
4217 Create file-backed memory-mapped pixel cache.
4220 (void) ClosePixelCacheOnDisk(cache_info);
4221 cache_info->type=MapCache;
4222 cache_info->mapped=MagickTrue;
4223 cache_info->metacontent=(void *) NULL;
4224 if (cache_info->metacontent_extent != 0)
4225 cache_info->metacontent=(void *) (cache_info->pixels+
4226 number_pixels*cache_info->number_channels);
4227 if (source_info.storage_class != UndefinedClass)
4229 status=ClonePixelCachePixels(cache_info,&source_info,
4231 RelinquishPixelCachePixels(&source_info);
4233 if (image->debug != MagickFalse)
4235 (void) FormatMagickSize(cache_info->length,MagickTrue,
4237 (void) FormatLocaleString(message,MaxTextExtent,
4238 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4239 cache_info->filename,cache_info->cache_filename,
4240 cache_info->file,(double) cache_info->columns,(double)
4241 cache_info->rows,(double) cache_info->number_channels,
4243 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4249 RelinquishMagickResource(MapResource,cache_info->length);
4252 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4254 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4255 RelinquishPixelCachePixels(&source_info);
4257 if (image->debug != MagickFalse)
4259 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4260 (void) FormatLocaleString(message,MaxTextExtent,
4261 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4262 cache_info->cache_filename,cache_info->file,(double)
4263 cache_info->columns,(double) cache_info->rows,(double)
4264 cache_info->number_channels,format);
4265 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4275 + P e r s i s t P i x e l C a c h e %
4279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4281 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4282 % persistent pixel cache is one that resides on disk and is not destroyed
4283 % when the program exits.
4285 % The format of the PersistPixelCache() method is:
4287 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4288 % const MagickBooleanType attach,MagickOffsetType *offset,
4289 % ExceptionInfo *exception)
4291 % A description of each parameter follows:
4293 % o image: the image.
4295 % o filename: the persistent pixel cache filename.
4297 % o attach: A value other than zero initializes the persistent pixel cache.
4299 % o initialize: A value other than zero initializes the persistent pixel
4302 % o offset: the offset in the persistent cache to store pixels.
4304 % o exception: return any errors or warnings in this structure.
4307 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4308 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4309 ExceptionInfo *exception)
4324 assert(image != (Image *) NULL);
4325 assert(image->signature == MagickSignature);
4326 if (image->debug != MagickFalse)
4327 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4328 assert(image->cache != (void *) NULL);
4329 assert(filename != (const char *) NULL);
4330 assert(offset != (MagickOffsetType *) NULL);
4331 page_size=GetMagickPageSize();
4332 cache_info=(CacheInfo *) image->cache;
4333 assert(cache_info->signature == MagickSignature);
4334 if (attach != MagickFalse)
4337 Attach existing persistent pixel cache.
4339 if (image->debug != MagickFalse)
4340 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4341 "attach persistent cache");
4342 (void) CopyMagickString(cache_info->cache_filename,filename,
4344 cache_info->type=DiskCache;
4345 cache_info->offset=(*offset);
4346 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4347 return(MagickFalse);
4348 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4351 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4352 (cache_info->reference_count == 1))
4354 LockSemaphoreInfo(cache_info->semaphore);
4355 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4356 (cache_info->reference_count == 1))
4362 Usurp existing persistent pixel cache.
4364 status=rename_utf8(cache_info->cache_filename,filename);
4367 (void) CopyMagickString(cache_info->cache_filename,filename,
4369 *offset+=cache_info->length+page_size-(cache_info->length %
4371 UnlockSemaphoreInfo(cache_info->semaphore);
4372 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4373 if (image->debug != MagickFalse)
4374 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4375 "Usurp resident persistent cache");
4379 UnlockSemaphoreInfo(cache_info->semaphore);
4382 Clone persistent pixel cache.
4384 clone_image=(*image);
4385 clone_info=(CacheInfo *) clone_image.cache;
4386 image->cache=ClonePixelCache(cache_info);
4387 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4388 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4389 cache_info->type=DiskCache;
4390 cache_info->offset=(*offset);
4391 cache_info=(CacheInfo *) image->cache;
4392 status=OpenPixelCache(image,IOMode,exception);
4393 if (status != MagickFalse)
4394 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4395 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4396 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4405 + Q u e u e A u t h e n t i c N e x u s %
4409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4411 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4412 % by the region rectangle and returns a pointer to the region. This region is
4413 % subsequently transferred from the pixel cache with
4414 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4415 % pixels are transferred, otherwise a NULL is returned.
4417 % The format of the QueueAuthenticNexus() method is:
4419 % Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4420 % const ssize_t y,const size_t columns,const size_t rows,
4421 % NexusInfo *nexus_info,ExceptionInfo *exception)
4423 % A description of each parameter follows:
4425 % o image: the image.
4427 % o x,y,columns,rows: These values define the perimeter of a region of
4430 % o nexus_info: the cache nexus to set.
4432 % o exception: return any errors or warnings in this structure.
4435 MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4436 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4437 ExceptionInfo *exception)
4452 Validate pixel cache geometry.
4454 assert(image != (const Image *) NULL);
4455 assert(image->signature == MagickSignature);
4456 assert(image->cache != (Cache) NULL);
4457 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4458 if (cache_info == (Cache) NULL)
4459 return((Quantum *) NULL);
4460 assert(cache_info->signature == MagickSignature);
4461 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4463 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4464 "NoPixelsDefinedInCache","`%s'",image->filename);
4465 return((Quantum *) NULL);
4467 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4468 (y >= (ssize_t) cache_info->rows))
4470 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4471 "PixelsAreNotAuthentic","`%s'",image->filename);
4472 return((Quantum *) NULL);
4474 offset=(MagickOffsetType) y*cache_info->columns+x;
4476 return((Quantum *) NULL);
4477 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4478 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4479 if ((MagickSizeType) offset >= number_pixels)
4480 return((Quantum *) NULL);
4486 region.width=columns;
4488 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4496 + 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 %
4500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4502 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4503 % defined by the region rectangle and returns a pointer to the region. This
4504 % region is subsequently transferred from the pixel cache with
4505 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4506 % pixels are transferred, otherwise a NULL is returned.
4508 % The format of the QueueAuthenticPixelsCache() method is:
4510 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4511 % const ssize_t y,const size_t columns,const size_t rows,
4512 % ExceptionInfo *exception)
4514 % A description of each parameter follows:
4516 % o image: the image.
4518 % o x,y,columns,rows: These values define the perimeter of a region of
4521 % o exception: return any errors or warnings in this structure.
4524 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4525 const ssize_t y,const size_t columns,const size_t rows,
4526 ExceptionInfo *exception)
4532 id = GetOpenMPThreadId();
4537 assert(image != (const Image *) NULL);
4538 assert(image->signature == MagickSignature);
4539 assert(image->cache != (Cache) NULL);
4540 cache_info=(CacheInfo *) image->cache;
4541 assert(cache_info->signature == MagickSignature);
4542 assert(id < (int) cache_info->number_threads);
4543 q=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4549 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4553 % Q u e u e A u t h e n t i c P i x e l s %
4557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4559 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4560 % successfully initialized a pointer to a Quantum array representing the
4561 % region is returned, otherwise NULL is returned. The returned pointer may
4562 % point to a temporary working buffer for the pixels or it may point to the
4563 % final location of the pixels in memory.
4565 % Write-only access means that any existing pixel values corresponding to
4566 % the region are ignored. This is useful if the initial image is being
4567 % created from scratch, or if the existing pixel values are to be
4568 % completely replaced without need to refer to their pre-existing values.
4569 % The application is free to read and write the pixel buffer returned by
4570 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4571 % initialize the pixel array values. Initializing pixel array values is the
4572 % application's responsibility.
4574 % Performance is maximized if the selected region is part of one row, or
4575 % one or more full rows, since then there is opportunity to access the
4576 % pixels in-place (without a copy) if the image is in memory, or in a
4577 % memory-mapped file. The returned pointer must *never* be deallocated
4580 % Pixels accessed via the returned pointer represent a simple array of type
4581 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4582 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4583 % obtain the meta-content (of type void) corresponding to the region.
4584 % Once the Quantum (and/or Quantum) array has been updated, the
4585 % changes must be saved back to the underlying image using
4586 % SyncAuthenticPixels() or they may be lost.
4588 % The format of the QueueAuthenticPixels() method is:
4590 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4591 % const ssize_t y,const size_t columns,const size_t rows,
4592 % ExceptionInfo *exception)
4594 % A description of each parameter follows:
4596 % o image: the image.
4598 % o x,y,columns,rows: These values define the perimeter of a region of
4601 % o exception: return any errors or warnings in this structure.
4604 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4605 const ssize_t y,const size_t columns,const size_t rows,
4606 ExceptionInfo *exception)
4612 id = GetOpenMPThreadId();
4617 assert(image != (Image *) NULL);
4618 assert(image->signature == MagickSignature);
4619 assert(image->cache != (Cache) NULL);
4620 cache_info=(CacheInfo *) image->cache;
4621 assert(cache_info->signature == MagickSignature);
4622 if (cache_info->methods.queue_authentic_pixels_handler !=
4623 (QueueAuthenticPixelsHandler) NULL)
4625 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4626 columns,rows,exception);
4629 assert(id < (int) cache_info->number_threads);
4630 q=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4640 + 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 %
4644 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4646 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4649 % The format of the ReadPixelCacheMetacontent() method is:
4651 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4652 % NexusInfo *nexus_info,ExceptionInfo *exception)
4654 % A description of each parameter follows:
4656 % o cache_info: the pixel cache.
4658 % o nexus_info: the cache nexus to read the metacontent.
4660 % o exception: return any errors or warnings in this structure.
4663 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4664 NexusInfo *nexus_info,ExceptionInfo *exception)
4677 register unsigned char
4683 if (cache_info->metacontent_extent == 0)
4684 return(MagickFalse);
4685 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4687 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4688 nexus_info->region.x;
4689 length=(MagickSizeType) nexus_info->region.width*
4690 cache_info->metacontent_extent;
4691 rows=nexus_info->region.height;
4693 q=(unsigned char *) nexus_info->metacontent;
4694 switch (cache_info->type)
4699 register unsigned char
4703 Read meta-content from memory.
4705 if ((cache_info->columns == nexus_info->region.width) &&
4706 (extent == (MagickSizeType) ((size_t) extent)))
4711 p=(unsigned char *) cache_info->metacontent+offset*
4712 cache_info->metacontent_extent;
4713 for (y=0; y < (ssize_t) rows; y++)
4715 (void) memcpy(q,p,(size_t) length);
4716 p+=cache_info->metacontent_extent*cache_info->columns;
4717 q+=cache_info->metacontent_extent*nexus_info->region.width;
4724 Read meta content from disk.
4726 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4728 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4729 cache_info->cache_filename);
4730 return(MagickFalse);
4732 if ((cache_info->columns == nexus_info->region.width) &&
4733 (extent <= MagickMaxBufferExtent))
4738 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4739 for (y=0; y < (ssize_t) rows; y++)
4741 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4742 cache_info->number_channels*sizeof(Quantum)+offset*
4743 cache_info->metacontent_extent,length,(unsigned char *) q);
4744 if ((MagickSizeType) count != length)
4746 offset+=cache_info->columns;
4747 q+=cache_info->metacontent_extent*nexus_info->region.width;
4749 if (y < (ssize_t) rows)
4751 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4752 cache_info->cache_filename);
4753 return(MagickFalse);
4760 if ((cache_info->debug != MagickFalse) &&
4761 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4762 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4763 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4764 nexus_info->region.width,(double) nexus_info->region.height,(double)
4765 nexus_info->region.x,(double) nexus_info->region.y);
4770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4774 + R e a d P i x e l C a c h e P i x e l s %
4778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4780 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4783 % The format of the ReadPixelCachePixels() method is:
4785 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4786 % NexusInfo *nexus_info,ExceptionInfo *exception)
4788 % A description of each parameter follows:
4790 % o cache_info: the pixel cache.
4792 % o nexus_info: the cache nexus to read the pixels.
4794 % o exception: return any errors or warnings in this structure.
4797 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4798 NexusInfo *nexus_info,ExceptionInfo *exception)
4817 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4819 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4820 nexus_info->region.x;
4821 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4823 rows=nexus_info->region.height;
4825 q=nexus_info->pixels;
4826 switch (cache_info->type)
4835 Read pixels from memory.
4837 if ((cache_info->columns == nexus_info->region.width) &&
4838 (extent == (MagickSizeType) ((size_t) extent)))
4843 p=cache_info->pixels+offset*cache_info->number_channels;
4844 for (y=0; y < (ssize_t) rows; y++)
4846 (void) memcpy(q,p,(size_t) length);
4847 p+=cache_info->number_channels*cache_info->columns;
4848 q+=cache_info->number_channels*nexus_info->region.width;
4855 Read pixels from disk.
4857 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4859 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4860 cache_info->cache_filename);
4861 return(MagickFalse);
4863 if ((cache_info->columns == nexus_info->region.width) &&
4864 (extent <= MagickMaxBufferExtent))
4869 for (y=0; y < (ssize_t) rows; y++)
4871 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4872 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4873 if ((MagickSizeType) count != length)
4875 offset+=cache_info->columns;
4876 q+=cache_info->number_channels*nexus_info->region.width;
4878 if (y < (ssize_t) rows)
4880 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4881 cache_info->cache_filename);
4882 return(MagickFalse);
4889 if ((cache_info->debug != MagickFalse) &&
4890 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4891 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4892 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4893 nexus_info->region.width,(double) nexus_info->region.height,(double)
4894 nexus_info->region.x,(double) nexus_info->region.y);
4899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4903 + R e f e r e n c e P i x e l C a c h e %
4907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4909 % ReferencePixelCache() increments the reference count associated with the
4910 % pixel cache returning a pointer to the cache.
4912 % The format of the ReferencePixelCache method is:
4914 % Cache ReferencePixelCache(Cache cache_info)
4916 % A description of each parameter follows:
4918 % o cache_info: the pixel cache.
4921 MagickPrivate Cache ReferencePixelCache(Cache cache)
4926 assert(cache != (Cache *) NULL);
4927 cache_info=(CacheInfo *) cache;
4928 assert(cache_info->signature == MagickSignature);
4929 LockSemaphoreInfo(cache_info->semaphore);
4930 cache_info->reference_count++;
4931 UnlockSemaphoreInfo(cache_info->semaphore);
4936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4940 + S e t P i x e l C a c h e M e t h o d s %
4944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4946 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4948 % The format of the SetPixelCacheMethods() method is:
4950 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4952 % A description of each parameter follows:
4954 % o cache: the pixel cache.
4956 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4959 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4964 GetOneAuthenticPixelFromHandler
4965 get_one_authentic_pixel_from_handler;
4967 GetOneVirtualPixelFromHandler
4968 get_one_virtual_pixel_from_handler;
4971 Set cache pixel methods.
4973 assert(cache != (Cache) NULL);
4974 assert(cache_methods != (CacheMethods *) NULL);
4975 cache_info=(CacheInfo *) cache;
4976 assert(cache_info->signature == MagickSignature);
4977 if (cache_info->debug != MagickFalse)
4978 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4979 cache_info->filename);
4980 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4981 cache_info->methods.get_virtual_pixel_handler=
4982 cache_methods->get_virtual_pixel_handler;
4983 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4984 cache_info->methods.destroy_pixel_handler=
4985 cache_methods->destroy_pixel_handler;
4986 if (cache_methods->get_virtual_metacontent_from_handler !=
4987 (GetVirtualMetacontentFromHandler) NULL)
4988 cache_info->methods.get_virtual_metacontent_from_handler=
4989 cache_methods->get_virtual_metacontent_from_handler;
4990 if (cache_methods->get_authentic_pixels_handler !=
4991 (GetAuthenticPixelsHandler) NULL)
4992 cache_info->methods.get_authentic_pixels_handler=
4993 cache_methods->get_authentic_pixels_handler;
4994 if (cache_methods->queue_authentic_pixels_handler !=
4995 (QueueAuthenticPixelsHandler) NULL)
4996 cache_info->methods.queue_authentic_pixels_handler=
4997 cache_methods->queue_authentic_pixels_handler;
4998 if (cache_methods->sync_authentic_pixels_handler !=
4999 (SyncAuthenticPixelsHandler) NULL)
5000 cache_info->methods.sync_authentic_pixels_handler=
5001 cache_methods->sync_authentic_pixels_handler;
5002 if (cache_methods->get_authentic_pixels_from_handler !=
5003 (GetAuthenticPixelsFromHandler) NULL)
5004 cache_info->methods.get_authentic_pixels_from_handler=
5005 cache_methods->get_authentic_pixels_from_handler;
5006 if (cache_methods->get_authentic_metacontent_from_handler !=
5007 (GetAuthenticMetacontentFromHandler) NULL)
5008 cache_info->methods.get_authentic_metacontent_from_handler=
5009 cache_methods->get_authentic_metacontent_from_handler;
5010 get_one_virtual_pixel_from_handler=
5011 cache_info->methods.get_one_virtual_pixel_from_handler;
5012 if (get_one_virtual_pixel_from_handler !=
5013 (GetOneVirtualPixelFromHandler) NULL)
5014 cache_info->methods.get_one_virtual_pixel_from_handler=
5015 cache_methods->get_one_virtual_pixel_from_handler;
5016 get_one_authentic_pixel_from_handler=
5017 cache_methods->get_one_authentic_pixel_from_handler;
5018 if (get_one_authentic_pixel_from_handler !=
5019 (GetOneAuthenticPixelFromHandler) NULL)
5020 cache_info->methods.get_one_authentic_pixel_from_handler=
5021 cache_methods->get_one_authentic_pixel_from_handler;
5025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5029 + S e t P i x e l C a c h e N e x u s P i x e l s %
5033 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5035 % SetPixelCacheNexusPixels() defines the region of the cache for the
5036 % specified cache nexus.
5038 % The format of the SetPixelCacheNexusPixels() method is:
5040 % Quantum SetPixelCacheNexusPixels(const Image *image,
5041 % const RectangleInfo *region,NexusInfo *nexus_info,
5042 % ExceptionInfo *exception)
5044 % A description of each parameter follows:
5046 % o image: the image.
5048 % o region: A pointer to the RectangleInfo structure that defines the
5049 % region of this particular cache nexus.
5051 % o nexus_info: the cache nexus to set.
5053 % o exception: return any errors or warnings in this structure.
5057 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5058 NexusInfo *nexus_info,ExceptionInfo *exception)
5060 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5061 return(MagickFalse);
5062 nexus_info->mapped=MagickFalse;
5063 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
5064 nexus_info->length);
5065 if (nexus_info->cache == (Quantum *) NULL)
5067 nexus_info->mapped=MagickTrue;
5068 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
5069 nexus_info->length);
5071 if (nexus_info->cache == (Quantum *) NULL)
5073 (void) ThrowMagickException(exception,GetMagickModule(),
5074 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5075 cache_info->filename);
5076 return(MagickFalse);
5081 static Quantum *SetPixelCacheNexusPixels(const Image *image,
5082 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5094 cache_info=(CacheInfo *) image->cache;
5095 assert(cache_info->signature == MagickSignature);
5096 if (cache_info->type == UndefinedCache)
5097 return((Quantum *) NULL);
5098 nexus_info->region=(*region);
5099 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5100 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5106 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5107 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5108 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5109 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5110 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5111 ((nexus_info->region.width == cache_info->columns) ||
5112 ((nexus_info->region.width % cache_info->columns) == 0)))))
5118 Pixels are accessed directly from memory.
5120 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5121 nexus_info->region.x;
5122 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5124 nexus_info->metacontent=(void *) NULL;
5125 if (cache_info->metacontent_extent != 0)
5126 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5127 offset*cache_info->metacontent_extent;
5128 return(nexus_info->pixels);
5132 Pixels are stored in a cache region until they are synced to the cache.
5134 number_pixels=(MagickSizeType) nexus_info->region.width*
5135 nexus_info->region.height;
5136 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
5137 if (cache_info->metacontent_extent != 0)
5138 length+=number_pixels*cache_info->metacontent_extent;
5139 if (nexus_info->cache == (Quantum *) NULL)
5141 nexus_info->length=length;
5142 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5143 if (status == MagickFalse)
5145 nexus_info->length=0;
5146 return((Quantum *) NULL);
5150 if (nexus_info->length != length)
5152 RelinquishCacheNexusPixels(nexus_info);
5153 nexus_info->length=length;
5154 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5155 if (status == MagickFalse)
5157 nexus_info->length=0;
5158 return((Quantum *) NULL);
5161 nexus_info->pixels=nexus_info->cache;
5162 nexus_info->metacontent=(void *) NULL;
5163 if (cache_info->metacontent_extent != 0)
5164 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
5165 cache_info->number_channels);
5166 return(nexus_info->pixels);
5170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5174 % 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 %
5178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5180 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5181 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5182 % access that is outside the boundaries of the image cache.
5184 % The format of the SetPixelCacheVirtualMethod() method is:
5186 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5187 % const VirtualPixelMethod virtual_pixel_method)
5189 % A description of each parameter follows:
5191 % o image: the image.
5193 % o virtual_pixel_method: choose the type of virtual pixel.
5196 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5197 const VirtualPixelMethod virtual_pixel_method)
5205 assert(image != (Image *) NULL);
5206 assert(image->signature == MagickSignature);
5207 if (image->debug != MagickFalse)
5208 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5209 assert(image->cache != (Cache) NULL);
5210 cache_info=(CacheInfo *) image->cache;
5211 assert(cache_info->signature == MagickSignature);
5212 method=cache_info->virtual_pixel_method;
5213 cache_info->virtual_pixel_method=virtual_pixel_method;
5218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5222 + 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 %
5226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5228 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5229 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5230 % is synced, otherwise MagickFalse.
5232 % The format of the SyncAuthenticPixelCacheNexus() method is:
5234 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5235 % NexusInfo *nexus_info,ExceptionInfo *exception)
5237 % A description of each parameter follows:
5239 % o image: the image.
5241 % o nexus_info: the cache nexus to sync.
5243 % o exception: return any errors or warnings in this structure.
5246 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5247 NexusInfo *nexus_info,ExceptionInfo *exception)
5256 Transfer pixels to the cache.
5258 assert(image != (Image *) NULL);
5259 assert(image->signature == MagickSignature);
5260 if (image->cache == (Cache) NULL)
5261 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5262 cache_info=(CacheInfo *) image->cache;
5263 assert(cache_info->signature == MagickSignature);
5264 if (cache_info->type == UndefinedCache)
5265 return(MagickFalse);
5266 if ((image->clip_mask != (Image *) NULL) &&
5267 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5268 return(MagickFalse);
5269 if ((image->mask != (Image *) NULL) &&
5270 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5271 return(MagickFalse);
5272 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5274 assert(cache_info->signature == MagickSignature);
5275 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5276 if ((cache_info->metacontent_extent != 0) &&
5277 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5278 return(MagickFalse);
5283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5287 + S y n c A u t h e n t i c P i x e l C a c h e %
5291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5293 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5294 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5295 % otherwise MagickFalse.
5297 % The format of the SyncAuthenticPixelsCache() method is:
5299 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5300 % ExceptionInfo *exception)
5302 % A description of each parameter follows:
5304 % o image: the image.
5306 % o exception: return any errors or warnings in this structure.
5309 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5310 ExceptionInfo *exception)
5316 id = GetOpenMPThreadId();
5321 assert(image != (Image *) NULL);
5322 assert(image->signature == MagickSignature);
5323 assert(image->cache != (Cache) NULL);
5324 cache_info=(CacheInfo *) image->cache;
5325 assert(cache_info->signature == MagickSignature);
5326 assert(id < (int) cache_info->number_threads);
5327 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5337 % S y n c A u t h e n t i c P i x e l s %
5341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5343 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5344 % The method returns MagickTrue if the pixel region is flushed, otherwise
5347 % The format of the SyncAuthenticPixels() method is:
5349 % MagickBooleanType SyncAuthenticPixels(Image *image,
5350 % ExceptionInfo *exception)
5352 % A description of each parameter follows:
5354 % o image: the image.
5356 % o exception: return any errors or warnings in this structure.
5359 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5360 ExceptionInfo *exception)
5366 id = GetOpenMPThreadId();
5371 assert(image != (Image *) NULL);
5372 assert(image->signature == MagickSignature);
5373 assert(image->cache != (Cache) NULL);
5374 cache_info=(CacheInfo *) image->cache;
5375 assert(cache_info->signature == MagickSignature);
5376 if (cache_info->methods.sync_authentic_pixels_handler !=
5377 (SyncAuthenticPixelsHandler) NULL)
5379 status=cache_info->methods.sync_authentic_pixels_handler(image,
5383 assert(id < (int) cache_info->number_threads);
5384 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5394 + S y n c I m a g e P i x e l C a c h e %
5398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5400 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5401 % The method returns MagickTrue if the pixel region is flushed, otherwise
5404 % The format of the SyncImagePixelCache() method is:
5406 % MagickBooleanType SyncImagePixelCache(Image *image,
5407 % ExceptionInfo *exception)
5409 % A description of each parameter follows:
5411 % o image: the image.
5413 % o exception: return any errors or warnings in this structure.
5416 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5417 ExceptionInfo *exception)
5422 assert(image != (Image *) NULL);
5423 assert(exception != (ExceptionInfo *) NULL);
5424 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5425 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5433 + 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 %
5437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5439 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5440 % of the pixel cache.
5442 % The format of the WritePixelCacheMetacontent() method is:
5444 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5445 % NexusInfo *nexus_info,ExceptionInfo *exception)
5447 % A description of each parameter follows:
5449 % o cache_info: the pixel cache.
5451 % o nexus_info: the cache nexus to write the meta-content.
5453 % o exception: return any errors or warnings in this structure.
5456 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5457 NexusInfo *nexus_info,ExceptionInfo *exception)
5467 register const unsigned char
5476 if (cache_info->metacontent_extent == 0)
5477 return(MagickFalse);
5478 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5480 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5481 nexus_info->region.x;
5482 length=(MagickSizeType) nexus_info->region.width*
5483 cache_info->metacontent_extent;
5484 rows=nexus_info->region.height;
5485 extent=(MagickSizeType) length*rows;
5486 p=(unsigned char *) nexus_info->metacontent;
5487 switch (cache_info->type)
5492 register unsigned char
5496 Write associated pixels to memory.
5498 if ((cache_info->columns == nexus_info->region.width) &&
5499 (extent == (MagickSizeType) ((size_t) extent)))
5504 q=(unsigned char *) cache_info->metacontent+offset*
5505 cache_info->metacontent_extent;
5506 for (y=0; y < (ssize_t) rows; y++)
5508 (void) memcpy(q,p,(size_t) length);
5509 p+=nexus_info->region.width*cache_info->metacontent_extent;
5510 q+=cache_info->columns*cache_info->metacontent_extent;
5517 Write associated pixels to disk.
5519 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5521 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5522 cache_info->cache_filename);
5523 return(MagickFalse);
5525 if ((cache_info->columns == nexus_info->region.width) &&
5526 (extent <= MagickMaxBufferExtent))
5531 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5532 for (y=0; y < (ssize_t) rows; y++)
5534 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5535 cache_info->number_channels*sizeof(Quantum)+offset*
5536 cache_info->metacontent_extent,length,(const unsigned char *) p);
5537 if ((MagickSizeType) count != length)
5539 p+=nexus_info->region.width*cache_info->metacontent_extent;
5540 offset+=cache_info->columns;
5542 if (y < (ssize_t) rows)
5544 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5545 cache_info->cache_filename);
5546 return(MagickFalse);
5553 if ((cache_info->debug != MagickFalse) &&
5554 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5555 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5556 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5557 nexus_info->region.width,(double) nexus_info->region.height,(double)
5558 nexus_info->region.x,(double) nexus_info->region.y);
5563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5567 + W r i t e C a c h e P i x e l s %
5571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5573 % WritePixelCachePixels() writes image pixels to the specified region of the
5576 % The format of the WritePixelCachePixels() method is:
5578 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5579 % NexusInfo *nexus_info,ExceptionInfo *exception)
5581 % A description of each parameter follows:
5583 % o cache_info: the pixel cache.
5585 % o nexus_info: the cache nexus to write the pixels.
5587 % o exception: return any errors or warnings in this structure.
5590 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5591 NexusInfo *nexus_info,ExceptionInfo *exception)
5601 register const Quantum
5610 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5612 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5613 nexus_info->region.x;
5614 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5616 rows=nexus_info->region.height;
5618 p=nexus_info->pixels;
5619 switch (cache_info->type)
5628 Write pixels to memory.
5630 if ((cache_info->columns == nexus_info->region.width) &&
5631 (extent == (MagickSizeType) ((size_t) extent)))
5636 q=cache_info->pixels+offset*cache_info->number_channels;
5637 for (y=0; y < (ssize_t) rows; y++)
5639 (void) memcpy(q,p,(size_t) length);
5640 p+=nexus_info->region.width*cache_info->number_channels;
5641 q+=cache_info->columns*cache_info->number_channels;
5648 Write pixels to disk.
5650 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5652 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5653 cache_info->cache_filename);
5654 return(MagickFalse);
5656 if ((cache_info->columns == nexus_info->region.width) &&
5657 (extent <= MagickMaxBufferExtent))
5662 for (y=0; y < (ssize_t) rows; y++)
5664 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5665 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5667 if ((MagickSizeType) count != length)
5669 p+=nexus_info->region.width*cache_info->number_channels;
5670 offset+=cache_info->columns;
5672 if (y < (ssize_t) rows)
5674 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5675 cache_info->cache_filename);
5676 return(MagickFalse);
5683 if ((cache_info->debug != MagickFalse) &&
5684 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5685 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5686 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5687 nexus_info->region.width,(double) nexus_info->region.height,(double)
5688 nexus_info->region.x,(double) nexus_info->region.y);