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,MagickTrue,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 if (length != (MagickSizeType) ((size_t) length))
4197 cache_info->type=DiskCache;
4200 status=AcquireMagickResource(MapResource,cache_info->length);
4201 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4202 (cache_info->type != MemoryCache))
4203 cache_info->type=DiskCache;
4206 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4207 cache_info->offset,(size_t) cache_info->length);
4208 if (cache_info->pixels == (Quantum *) NULL)
4210 cache_info->type=DiskCache;
4211 cache_info->pixels=source_info.pixels;
4216 Create file-backed memory-mapped pixel cache.
4219 (void) ClosePixelCacheOnDisk(cache_info);
4220 cache_info->type=MapCache;
4221 cache_info->mapped=MagickTrue;
4222 cache_info->metacontent=(void *) NULL;
4223 if (cache_info->metacontent_extent != 0)
4224 cache_info->metacontent=(void *) (cache_info->pixels+
4225 number_pixels*cache_info->number_channels);
4226 if (source_info.storage_class != UndefinedClass)
4228 status=ClonePixelCachePixels(cache_info,&source_info,
4230 RelinquishPixelCachePixels(&source_info);
4232 if (image->debug != MagickFalse)
4234 (void) FormatMagickSize(cache_info->length,MagickTrue,
4236 (void) FormatLocaleString(message,MaxTextExtent,
4237 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4238 cache_info->filename,cache_info->cache_filename,
4239 cache_info->file,(double) cache_info->columns,(double)
4240 cache_info->rows,(double) cache_info->number_channels,
4242 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4248 RelinquishMagickResource(MapResource,cache_info->length);
4251 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4253 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4254 RelinquishPixelCachePixels(&source_info);
4256 if (image->debug != MagickFalse)
4258 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4259 (void) FormatLocaleString(message,MaxTextExtent,
4260 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4261 cache_info->cache_filename,cache_info->file,(double)
4262 cache_info->columns,(double) cache_info->rows,(double)
4263 cache_info->number_channels,format);
4264 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4274 + P e r s i s t P i x e l C a c h e %
4278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4280 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4281 % persistent pixel cache is one that resides on disk and is not destroyed
4282 % when the program exits.
4284 % The format of the PersistPixelCache() method is:
4286 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4287 % const MagickBooleanType attach,MagickOffsetType *offset,
4288 % ExceptionInfo *exception)
4290 % A description of each parameter follows:
4292 % o image: the image.
4294 % o filename: the persistent pixel cache filename.
4296 % o attach: A value other than zero initializes the persistent pixel cache.
4298 % o initialize: A value other than zero initializes the persistent pixel
4301 % o offset: the offset in the persistent cache to store pixels.
4303 % o exception: return any errors or warnings in this structure.
4306 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4307 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4308 ExceptionInfo *exception)
4323 assert(image != (Image *) NULL);
4324 assert(image->signature == MagickSignature);
4325 if (image->debug != MagickFalse)
4326 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4327 assert(image->cache != (void *) NULL);
4328 assert(filename != (const char *) NULL);
4329 assert(offset != (MagickOffsetType *) NULL);
4330 page_size=GetMagickPageSize();
4331 cache_info=(CacheInfo *) image->cache;
4332 assert(cache_info->signature == MagickSignature);
4333 if (attach != MagickFalse)
4336 Attach existing persistent pixel cache.
4338 if (image->debug != MagickFalse)
4339 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4340 "attach persistent cache");
4341 (void) CopyMagickString(cache_info->cache_filename,filename,
4343 cache_info->type=DiskCache;
4344 cache_info->offset=(*offset);
4345 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4346 return(MagickFalse);
4347 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4350 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4351 (cache_info->reference_count == 1))
4353 LockSemaphoreInfo(cache_info->semaphore);
4354 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4355 (cache_info->reference_count == 1))
4361 Usurp existing persistent pixel cache.
4363 status=rename_utf8(cache_info->cache_filename,filename);
4366 (void) CopyMagickString(cache_info->cache_filename,filename,
4368 *offset+=cache_info->length+page_size-(cache_info->length %
4370 UnlockSemaphoreInfo(cache_info->semaphore);
4371 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4372 if (image->debug != MagickFalse)
4373 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4374 "Usurp resident persistent cache");
4378 UnlockSemaphoreInfo(cache_info->semaphore);
4381 Clone persistent pixel cache.
4383 clone_image=(*image);
4384 clone_info=(CacheInfo *) clone_image.cache;
4385 image->cache=ClonePixelCache(cache_info);
4386 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4387 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4388 cache_info->type=DiskCache;
4389 cache_info->offset=(*offset);
4390 cache_info=(CacheInfo *) image->cache;
4391 status=OpenPixelCache(image,IOMode,exception);
4392 if (status != MagickFalse)
4393 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4394 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4395 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4404 + Q u e u e A u t h e n t i c N e x u s %
4408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4410 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4411 % by the region rectangle and returns a pointer to the region. This region is
4412 % subsequently transferred from the pixel cache with
4413 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4414 % pixels are transferred, otherwise a NULL is returned.
4416 % The format of the QueueAuthenticNexus() method is:
4418 % Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4419 % const ssize_t y,const size_t columns,const size_t rows,
4420 % const MagickBooleanType clone,NexusInfo *nexus_info,
4421 % 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 clone: clone the pixel cache.
4434 % o exception: return any errors or warnings in this structure.
4437 MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4438 const ssize_t y,const size_t columns,const size_t rows,
4439 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4454 Validate pixel cache geometry.
4456 assert(image != (const Image *) NULL);
4457 assert(image->signature == MagickSignature);
4458 assert(image->cache != (Cache) NULL);
4459 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4460 if (cache_info == (Cache) NULL)
4461 return((Quantum *) NULL);
4462 assert(cache_info->signature == MagickSignature);
4463 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4465 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4466 "NoPixelsDefinedInCache","`%s'",image->filename);
4467 return((Quantum *) NULL);
4469 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4470 (y >= (ssize_t) cache_info->rows))
4472 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4473 "PixelsAreNotAuthentic","`%s'",image->filename);
4474 return((Quantum *) NULL);
4476 offset=(MagickOffsetType) y*cache_info->columns+x;
4478 return((Quantum *) NULL);
4479 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4480 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4481 if ((MagickSizeType) offset >= number_pixels)
4482 return((Quantum *) NULL);
4488 region.width=columns;
4490 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4498 + 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 %
4502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4504 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4505 % defined by the region rectangle and returns a pointer to the region. This
4506 % region is subsequently transferred from the pixel cache with
4507 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4508 % pixels are transferred, otherwise a NULL is returned.
4510 % The format of the QueueAuthenticPixelsCache() method is:
4512 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4513 % const ssize_t y,const size_t columns,const size_t rows,
4514 % ExceptionInfo *exception)
4516 % A description of each parameter follows:
4518 % o image: the image.
4520 % o x,y,columns,rows: These values define the perimeter of a region of
4523 % o exception: return any errors or warnings in this structure.
4526 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4527 const ssize_t y,const size_t columns,const size_t rows,
4528 ExceptionInfo *exception)
4534 id = GetOpenMPThreadId();
4539 assert(image != (const Image *) NULL);
4540 assert(image->signature == MagickSignature);
4541 assert(image->cache != (Cache) NULL);
4542 cache_info=(CacheInfo *) image->cache;
4543 assert(cache_info->signature == MagickSignature);
4544 assert(id < (int) cache_info->number_threads);
4545 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4546 cache_info->nexus_info[id],exception);
4551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4555 % Q u e u e A u t h e n t i c P i x e l s %
4559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4561 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4562 % successfully initialized a pointer to a Quantum array representing the
4563 % region is returned, otherwise NULL is returned. The returned pointer may
4564 % point to a temporary working buffer for the pixels or it may point to the
4565 % final location of the pixels in memory.
4567 % Write-only access means that any existing pixel values corresponding to
4568 % the region are ignored. This is useful if the initial image is being
4569 % created from scratch, or if the existing pixel values are to be
4570 % completely replaced without need to refer to their pre-existing values.
4571 % The application is free to read and write the pixel buffer returned by
4572 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4573 % initialize the pixel array values. Initializing pixel array values is the
4574 % application's responsibility.
4576 % Performance is maximized if the selected region is part of one row, or
4577 % one or more full rows, since then there is opportunity to access the
4578 % pixels in-place (without a copy) if the image is in memory, or in a
4579 % memory-mapped file. The returned pointer must *never* be deallocated
4582 % Pixels accessed via the returned pointer represent a simple array of type
4583 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4584 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4585 % obtain the meta-content (of type void) corresponding to the region.
4586 % Once the Quantum (and/or Quantum) array has been updated, the
4587 % changes must be saved back to the underlying image using
4588 % SyncAuthenticPixels() or they may be lost.
4590 % The format of the QueueAuthenticPixels() method is:
4592 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4593 % const ssize_t y,const size_t columns,const size_t rows,
4594 % ExceptionInfo *exception)
4596 % A description of each parameter follows:
4598 % o image: the image.
4600 % o x,y,columns,rows: These values define the perimeter of a region of
4603 % o exception: return any errors or warnings in this structure.
4606 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4607 const ssize_t y,const size_t columns,const size_t rows,
4608 ExceptionInfo *exception)
4614 id = GetOpenMPThreadId();
4619 assert(image != (Image *) NULL);
4620 assert(image->signature == MagickSignature);
4621 assert(image->cache != (Cache) NULL);
4622 cache_info=(CacheInfo *) image->cache;
4623 assert(cache_info->signature == MagickSignature);
4624 if (cache_info->methods.queue_authentic_pixels_handler !=
4625 (QueueAuthenticPixelsHandler) NULL)
4627 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4628 columns,rows,exception);
4631 assert(id < (int) cache_info->number_threads);
4632 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4633 cache_info->nexus_info[id],exception);
4638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4642 + 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 %
4646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4648 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4651 % The format of the ReadPixelCacheMetacontent() method is:
4653 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4654 % NexusInfo *nexus_info,ExceptionInfo *exception)
4656 % A description of each parameter follows:
4658 % o cache_info: the pixel cache.
4660 % o nexus_info: the cache nexus to read the metacontent.
4662 % o exception: return any errors or warnings in this structure.
4665 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4666 NexusInfo *nexus_info,ExceptionInfo *exception)
4679 register unsigned char
4685 if (cache_info->metacontent_extent == 0)
4686 return(MagickFalse);
4687 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4689 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4690 nexus_info->region.x;
4691 length=(MagickSizeType) nexus_info->region.width*
4692 cache_info->metacontent_extent;
4693 rows=nexus_info->region.height;
4695 q=(unsigned char *) nexus_info->metacontent;
4696 switch (cache_info->type)
4701 register unsigned char
4705 Read meta-content from memory.
4707 if ((cache_info->columns == nexus_info->region.width) &&
4708 (extent == (MagickSizeType) ((size_t) extent)))
4713 p=(unsigned char *) cache_info->metacontent+offset*
4714 cache_info->metacontent_extent;
4715 for (y=0; y < (ssize_t) rows; y++)
4717 (void) memcpy(q,p,(size_t) length);
4718 p+=cache_info->metacontent_extent*cache_info->columns;
4719 q+=cache_info->metacontent_extent*nexus_info->region.width;
4726 Read meta content from disk.
4728 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4730 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4731 cache_info->cache_filename);
4732 return(MagickFalse);
4734 if ((cache_info->columns == nexus_info->region.width) &&
4735 (extent <= MagickMaxBufferExtent))
4740 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4741 for (y=0; y < (ssize_t) rows; y++)
4743 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4744 cache_info->number_channels*sizeof(Quantum)+offset*
4745 cache_info->metacontent_extent,length,(unsigned char *) q);
4746 if ((MagickSizeType) count != length)
4748 offset+=cache_info->columns;
4749 q+=cache_info->metacontent_extent*nexus_info->region.width;
4751 if (y < (ssize_t) rows)
4753 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4754 cache_info->cache_filename);
4755 return(MagickFalse);
4762 if ((cache_info->debug != MagickFalse) &&
4763 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4764 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4765 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4766 nexus_info->region.width,(double) nexus_info->region.height,(double)
4767 nexus_info->region.x,(double) nexus_info->region.y);
4772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4776 + R e a d P i x e l C a c h e P i x e l s %
4780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4782 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4785 % The format of the ReadPixelCachePixels() method is:
4787 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4788 % NexusInfo *nexus_info,ExceptionInfo *exception)
4790 % A description of each parameter follows:
4792 % o cache_info: the pixel cache.
4794 % o nexus_info: the cache nexus to read the pixels.
4796 % o exception: return any errors or warnings in this structure.
4799 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4800 NexusInfo *nexus_info,ExceptionInfo *exception)
4819 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4821 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4822 nexus_info->region.x;
4823 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4825 rows=nexus_info->region.height;
4827 q=nexus_info->pixels;
4828 switch (cache_info->type)
4837 Read pixels from memory.
4839 if ((cache_info->columns == nexus_info->region.width) &&
4840 (extent == (MagickSizeType) ((size_t) extent)))
4845 p=cache_info->pixels+offset*cache_info->number_channels;
4846 for (y=0; y < (ssize_t) rows; y++)
4848 (void) memcpy(q,p,(size_t) length);
4849 p+=cache_info->number_channels*cache_info->columns;
4850 q+=cache_info->number_channels*nexus_info->region.width;
4857 Read pixels from disk.
4859 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4861 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4862 cache_info->cache_filename);
4863 return(MagickFalse);
4865 if ((cache_info->columns == nexus_info->region.width) &&
4866 (extent <= MagickMaxBufferExtent))
4871 for (y=0; y < (ssize_t) rows; y++)
4873 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4874 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4875 if ((MagickSizeType) count != length)
4877 offset+=cache_info->columns;
4878 q+=cache_info->number_channels*nexus_info->region.width;
4880 if (y < (ssize_t) rows)
4882 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4883 cache_info->cache_filename);
4884 return(MagickFalse);
4891 if ((cache_info->debug != MagickFalse) &&
4892 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4893 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4894 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4895 nexus_info->region.width,(double) nexus_info->region.height,(double)
4896 nexus_info->region.x,(double) nexus_info->region.y);
4901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4905 + R e f e r e n c e P i x e l C a c h e %
4909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4911 % ReferencePixelCache() increments the reference count associated with the
4912 % pixel cache returning a pointer to the cache.
4914 % The format of the ReferencePixelCache method is:
4916 % Cache ReferencePixelCache(Cache cache_info)
4918 % A description of each parameter follows:
4920 % o cache_info: the pixel cache.
4923 MagickPrivate Cache ReferencePixelCache(Cache cache)
4928 assert(cache != (Cache *) NULL);
4929 cache_info=(CacheInfo *) cache;
4930 assert(cache_info->signature == MagickSignature);
4931 LockSemaphoreInfo(cache_info->semaphore);
4932 cache_info->reference_count++;
4933 UnlockSemaphoreInfo(cache_info->semaphore);
4938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4942 + S e t P i x e l C a c h e M e t h o d s %
4946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4948 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4950 % The format of the SetPixelCacheMethods() method is:
4952 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4954 % A description of each parameter follows:
4956 % o cache: the pixel cache.
4958 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4961 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4966 GetOneAuthenticPixelFromHandler
4967 get_one_authentic_pixel_from_handler;
4969 GetOneVirtualPixelFromHandler
4970 get_one_virtual_pixel_from_handler;
4973 Set cache pixel methods.
4975 assert(cache != (Cache) NULL);
4976 assert(cache_methods != (CacheMethods *) NULL);
4977 cache_info=(CacheInfo *) cache;
4978 assert(cache_info->signature == MagickSignature);
4979 if (cache_info->debug != MagickFalse)
4980 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4981 cache_info->filename);
4982 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4983 cache_info->methods.get_virtual_pixel_handler=
4984 cache_methods->get_virtual_pixel_handler;
4985 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4986 cache_info->methods.destroy_pixel_handler=
4987 cache_methods->destroy_pixel_handler;
4988 if (cache_methods->get_virtual_metacontent_from_handler !=
4989 (GetVirtualMetacontentFromHandler) NULL)
4990 cache_info->methods.get_virtual_metacontent_from_handler=
4991 cache_methods->get_virtual_metacontent_from_handler;
4992 if (cache_methods->get_authentic_pixels_handler !=
4993 (GetAuthenticPixelsHandler) NULL)
4994 cache_info->methods.get_authentic_pixels_handler=
4995 cache_methods->get_authentic_pixels_handler;
4996 if (cache_methods->queue_authentic_pixels_handler !=
4997 (QueueAuthenticPixelsHandler) NULL)
4998 cache_info->methods.queue_authentic_pixels_handler=
4999 cache_methods->queue_authentic_pixels_handler;
5000 if (cache_methods->sync_authentic_pixels_handler !=
5001 (SyncAuthenticPixelsHandler) NULL)
5002 cache_info->methods.sync_authentic_pixels_handler=
5003 cache_methods->sync_authentic_pixels_handler;
5004 if (cache_methods->get_authentic_pixels_from_handler !=
5005 (GetAuthenticPixelsFromHandler) NULL)
5006 cache_info->methods.get_authentic_pixels_from_handler=
5007 cache_methods->get_authentic_pixels_from_handler;
5008 if (cache_methods->get_authentic_metacontent_from_handler !=
5009 (GetAuthenticMetacontentFromHandler) NULL)
5010 cache_info->methods.get_authentic_metacontent_from_handler=
5011 cache_methods->get_authentic_metacontent_from_handler;
5012 get_one_virtual_pixel_from_handler=
5013 cache_info->methods.get_one_virtual_pixel_from_handler;
5014 if (get_one_virtual_pixel_from_handler !=
5015 (GetOneVirtualPixelFromHandler) NULL)
5016 cache_info->methods.get_one_virtual_pixel_from_handler=
5017 cache_methods->get_one_virtual_pixel_from_handler;
5018 get_one_authentic_pixel_from_handler=
5019 cache_methods->get_one_authentic_pixel_from_handler;
5020 if (get_one_authentic_pixel_from_handler !=
5021 (GetOneAuthenticPixelFromHandler) NULL)
5022 cache_info->methods.get_one_authentic_pixel_from_handler=
5023 cache_methods->get_one_authentic_pixel_from_handler;
5027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5031 + S e t P i x e l C a c h e N e x u s P i x e l s %
5035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5037 % SetPixelCacheNexusPixels() defines the region of the cache for the
5038 % specified cache nexus.
5040 % The format of the SetPixelCacheNexusPixels() method is:
5042 % Quantum SetPixelCacheNexusPixels(const Image *image,
5043 % const RectangleInfo *region,NexusInfo *nexus_info,
5044 % ExceptionInfo *exception)
5046 % A description of each parameter follows:
5048 % o image: the image.
5050 % o region: A pointer to the RectangleInfo structure that defines the
5051 % region of this particular cache nexus.
5053 % o nexus_info: the cache nexus to set.
5055 % o exception: return any errors or warnings in this structure.
5059 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5060 NexusInfo *nexus_info,ExceptionInfo *exception)
5062 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5063 return(MagickFalse);
5064 nexus_info->mapped=MagickFalse;
5065 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
5066 nexus_info->length);
5067 if (nexus_info->cache == (Quantum *) NULL)
5069 nexus_info->mapped=MagickTrue;
5070 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
5071 nexus_info->length);
5073 if (nexus_info->cache == (Quantum *) NULL)
5075 (void) ThrowMagickException(exception,GetMagickModule(),
5076 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5077 cache_info->filename);
5078 return(MagickFalse);
5083 static Quantum *SetPixelCacheNexusPixels(const Image *image,
5084 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5096 cache_info=(CacheInfo *) image->cache;
5097 assert(cache_info->signature == MagickSignature);
5098 if (cache_info->type == UndefinedCache)
5099 return((Quantum *) NULL);
5100 nexus_info->region=(*region);
5101 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5102 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5108 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5109 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5110 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5111 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5112 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5113 ((nexus_info->region.width == cache_info->columns) ||
5114 ((nexus_info->region.width % cache_info->columns) == 0)))))
5120 Pixels are accessed directly from memory.
5122 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5123 nexus_info->region.x;
5124 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5126 nexus_info->metacontent=(void *) NULL;
5127 if (cache_info->metacontent_extent != 0)
5128 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5129 offset*cache_info->metacontent_extent;
5130 return(nexus_info->pixels);
5134 Pixels are stored in a cache region until they are synced to the cache.
5136 number_pixels=(MagickSizeType) nexus_info->region.width*
5137 nexus_info->region.height;
5138 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
5139 if (cache_info->metacontent_extent != 0)
5140 length+=number_pixels*cache_info->metacontent_extent;
5141 if (nexus_info->cache == (Quantum *) NULL)
5143 nexus_info->length=length;
5144 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5145 if (status == MagickFalse)
5147 nexus_info->length=0;
5148 return((Quantum *) NULL);
5152 if (nexus_info->length != length)
5154 RelinquishCacheNexusPixels(nexus_info);
5155 nexus_info->length=length;
5156 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5157 if (status == MagickFalse)
5159 nexus_info->length=0;
5160 return((Quantum *) NULL);
5163 nexus_info->pixels=nexus_info->cache;
5164 nexus_info->metacontent=(void *) NULL;
5165 if (cache_info->metacontent_extent != 0)
5166 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
5167 cache_info->number_channels);
5168 return(nexus_info->pixels);
5172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5176 % 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 %
5180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5182 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5183 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5184 % access that is outside the boundaries of the image cache.
5186 % The format of the SetPixelCacheVirtualMethod() method is:
5188 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5189 % const VirtualPixelMethod virtual_pixel_method)
5191 % A description of each parameter follows:
5193 % o image: the image.
5195 % o virtual_pixel_method: choose the type of virtual pixel.
5198 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5199 const VirtualPixelMethod virtual_pixel_method)
5207 assert(image != (Image *) NULL);
5208 assert(image->signature == MagickSignature);
5209 if (image->debug != MagickFalse)
5210 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5211 assert(image->cache != (Cache) NULL);
5212 cache_info=(CacheInfo *) image->cache;
5213 assert(cache_info->signature == MagickSignature);
5214 method=cache_info->virtual_pixel_method;
5215 cache_info->virtual_pixel_method=virtual_pixel_method;
5220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5224 + 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 %
5228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5230 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5231 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5232 % is synced, otherwise MagickFalse.
5234 % The format of the SyncAuthenticPixelCacheNexus() method is:
5236 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5237 % NexusInfo *nexus_info,ExceptionInfo *exception)
5239 % A description of each parameter follows:
5241 % o image: the image.
5243 % o nexus_info: the cache nexus to sync.
5245 % o exception: return any errors or warnings in this structure.
5248 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5249 NexusInfo *nexus_info,ExceptionInfo *exception)
5258 Transfer pixels to the cache.
5260 assert(image != (Image *) NULL);
5261 assert(image->signature == MagickSignature);
5262 if (image->cache == (Cache) NULL)
5263 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5264 cache_info=(CacheInfo *) image->cache;
5265 assert(cache_info->signature == MagickSignature);
5266 if (cache_info->type == UndefinedCache)
5267 return(MagickFalse);
5268 if ((image->clip_mask != (Image *) NULL) &&
5269 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5270 return(MagickFalse);
5271 if ((image->mask != (Image *) NULL) &&
5272 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5273 return(MagickFalse);
5274 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5276 assert(cache_info->signature == MagickSignature);
5277 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5278 if ((cache_info->metacontent_extent != 0) &&
5279 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5280 return(MagickFalse);
5285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5289 + S y n c A u t h e n t i c P i x e l C a c h e %
5293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5295 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5296 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5297 % otherwise MagickFalse.
5299 % The format of the SyncAuthenticPixelsCache() method is:
5301 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5302 % ExceptionInfo *exception)
5304 % A description of each parameter follows:
5306 % o image: the image.
5308 % o exception: return any errors or warnings in this structure.
5311 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5312 ExceptionInfo *exception)
5318 id = GetOpenMPThreadId();
5323 assert(image != (Image *) NULL);
5324 assert(image->signature == MagickSignature);
5325 assert(image->cache != (Cache) NULL);
5326 cache_info=(CacheInfo *) image->cache;
5327 assert(cache_info->signature == MagickSignature);
5328 assert(id < (int) cache_info->number_threads);
5329 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5339 % S y n c A u t h e n t i c P i x e l s %
5343 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5345 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5346 % The method returns MagickTrue if the pixel region is flushed, otherwise
5349 % The format of the SyncAuthenticPixels() method is:
5351 % MagickBooleanType SyncAuthenticPixels(Image *image,
5352 % ExceptionInfo *exception)
5354 % A description of each parameter follows:
5356 % o image: the image.
5358 % o exception: return any errors or warnings in this structure.
5361 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5362 ExceptionInfo *exception)
5368 id = GetOpenMPThreadId();
5373 assert(image != (Image *) NULL);
5374 assert(image->signature == MagickSignature);
5375 assert(image->cache != (Cache) NULL);
5376 cache_info=(CacheInfo *) image->cache;
5377 assert(cache_info->signature == MagickSignature);
5378 if (cache_info->methods.sync_authentic_pixels_handler !=
5379 (SyncAuthenticPixelsHandler) NULL)
5381 status=cache_info->methods.sync_authentic_pixels_handler(image,
5385 assert(id < (int) cache_info->number_threads);
5386 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5396 + S y n c I m a g e P i x e l C a c h e %
5400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5402 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5403 % The method returns MagickTrue if the pixel region is flushed, otherwise
5406 % The format of the SyncImagePixelCache() method is:
5408 % MagickBooleanType SyncImagePixelCache(Image *image,
5409 % ExceptionInfo *exception)
5411 % A description of each parameter follows:
5413 % o image: the image.
5415 % o exception: return any errors or warnings in this structure.
5418 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5419 ExceptionInfo *exception)
5424 assert(image != (Image *) NULL);
5425 assert(exception != (ExceptionInfo *) NULL);
5426 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5427 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5435 + 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 %
5439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5441 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5442 % of the pixel cache.
5444 % The format of the WritePixelCacheMetacontent() method is:
5446 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5447 % NexusInfo *nexus_info,ExceptionInfo *exception)
5449 % A description of each parameter follows:
5451 % o cache_info: the pixel cache.
5453 % o nexus_info: the cache nexus to write the meta-content.
5455 % o exception: return any errors or warnings in this structure.
5458 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5459 NexusInfo *nexus_info,ExceptionInfo *exception)
5469 register const unsigned char
5478 if (cache_info->metacontent_extent == 0)
5479 return(MagickFalse);
5480 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5482 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5483 nexus_info->region.x;
5484 length=(MagickSizeType) nexus_info->region.width*
5485 cache_info->metacontent_extent;
5486 rows=nexus_info->region.height;
5487 extent=(MagickSizeType) length*rows;
5488 p=(unsigned char *) nexus_info->metacontent;
5489 switch (cache_info->type)
5494 register unsigned char
5498 Write associated pixels to memory.
5500 if ((cache_info->columns == nexus_info->region.width) &&
5501 (extent == (MagickSizeType) ((size_t) extent)))
5506 q=(unsigned char *) cache_info->metacontent+offset*
5507 cache_info->metacontent_extent;
5508 for (y=0; y < (ssize_t) rows; y++)
5510 (void) memcpy(q,p,(size_t) length);
5511 p+=nexus_info->region.width*cache_info->metacontent_extent;
5512 q+=cache_info->columns*cache_info->metacontent_extent;
5519 Write associated pixels to disk.
5521 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5523 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5524 cache_info->cache_filename);
5525 return(MagickFalse);
5527 if ((cache_info->columns == nexus_info->region.width) &&
5528 (extent <= MagickMaxBufferExtent))
5533 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5534 for (y=0; y < (ssize_t) rows; y++)
5536 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5537 cache_info->number_channels*sizeof(Quantum)+offset*
5538 cache_info->metacontent_extent,length,(const unsigned char *) p);
5539 if ((MagickSizeType) count != length)
5541 p+=nexus_info->region.width*cache_info->metacontent_extent;
5542 offset+=cache_info->columns;
5544 if (y < (ssize_t) rows)
5546 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5547 cache_info->cache_filename);
5548 return(MagickFalse);
5555 if ((cache_info->debug != MagickFalse) &&
5556 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5557 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5558 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5559 nexus_info->region.width,(double) nexus_info->region.height,(double)
5560 nexus_info->region.x,(double) nexus_info->region.y);
5565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5569 + W r i t e C a c h e P i x e l s %
5573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5575 % WritePixelCachePixels() writes image pixels to the specified region of the
5578 % The format of the WritePixelCachePixels() method is:
5580 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5581 % NexusInfo *nexus_info,ExceptionInfo *exception)
5583 % A description of each parameter follows:
5585 % o cache_info: the pixel cache.
5587 % o nexus_info: the cache nexus to write the pixels.
5589 % o exception: return any errors or warnings in this structure.
5592 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5593 NexusInfo *nexus_info,ExceptionInfo *exception)
5603 register const Quantum
5612 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5614 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5615 nexus_info->region.x;
5616 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5618 rows=nexus_info->region.height;
5620 p=nexus_info->pixels;
5621 switch (cache_info->type)
5630 Write pixels to memory.
5632 if ((cache_info->columns == nexus_info->region.width) &&
5633 (extent == (MagickSizeType) ((size_t) extent)))
5638 q=cache_info->pixels+offset*cache_info->number_channels;
5639 for (y=0; y < (ssize_t) rows; y++)
5641 (void) memcpy(q,p,(size_t) length);
5642 p+=nexus_info->region.width*cache_info->number_channels;
5643 q+=cache_info->columns*cache_info->number_channels;
5650 Write pixels to disk.
5652 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5654 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5655 cache_info->cache_filename);
5656 return(MagickFalse);
5658 if ((cache_info->columns == nexus_info->region.width) &&
5659 (extent <= MagickMaxBufferExtent))
5664 for (y=0; y < (ssize_t) rows; y++)
5666 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5667 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5669 if ((MagickSizeType) count != length)
5671 p+=nexus_info->region.width*cache_info->number_channels;
5672 offset+=cache_info->columns;
5674 if (y < (ssize_t) rows)
5676 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5677 cache_info->cache_filename);
5678 return(MagickFalse);
5685 if ((cache_info->debug != MagickFalse) &&
5686 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5687 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5688 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5689 nexus_info->region.width,(double) nexus_info->region.height,(double)
5690 nexus_info->region.x,(double) nexus_info->region.y);