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[BlackPixelChannel]=image->background_color.black;
2151 pixel[AlphaPixelChannel]=image->background_color.alpha;
2152 return(MagickFalse);
2154 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2159 channel=GetPixelChannelMapChannel(image,i);
2160 pixel[channel]=q[i];
2166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2170 + 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 %
2174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2176 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2177 % location. The image background color is returned if an error occurs.
2179 % The format of the GetOneAuthenticPixelFromCache() method is:
2181 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2182 % const ssize_t x,const ssize_t y,Quantum *pixel,
2183 % ExceptionInfo *exception)
2185 % A description of each parameter follows:
2187 % o image: the image.
2189 % o x,y: These values define the location of the pixel to return.
2191 % o pixel: return a pixel at the specified (x,y) location.
2193 % o exception: return any errors or warnings in this structure.
2196 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2197 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2203 id = GetOpenMPThreadId();
2211 assert(image != (const Image *) NULL);
2212 assert(image->signature == MagickSignature);
2213 assert(image->cache != (Cache) NULL);
2214 cache_info=(CacheInfo *) image->cache;
2215 assert(cache_info->signature == MagickSignature);
2216 assert(id < (int) cache_info->number_threads);
2217 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2218 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2220 if (q == (Quantum *) NULL)
2222 pixel[RedPixelChannel]=image->background_color.red;
2223 pixel[GreenPixelChannel]=image->background_color.green;
2224 pixel[BluePixelChannel]=image->background_color.blue;
2225 pixel[BlackPixelChannel]=image->background_color.black;
2226 pixel[AlphaPixelChannel]=image->background_color.alpha;
2227 return(MagickFalse);
2229 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2234 channel=GetPixelChannelMapChannel(image,i);
2235 pixel[channel]=q[i];
2241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2245 % G e t O n e V i r t u a l M a g i c k P i x e l %
2249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2251 % GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2252 % location. The image background color is returned if an error occurs. If
2253 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2255 % The format of the GetOneVirtualMagickPixel() method is:
2257 % MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2258 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2259 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2261 % A description of each parameter follows:
2263 % o image: the image.
2265 % o virtual_pixel_method: the virtual pixel method.
2267 % o x,y: these values define the location of the pixel to return.
2269 % o pixel: return a pixel at the specified (x,y) location.
2271 % o exception: return any errors or warnings in this structure.
2274 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2275 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2276 PixelInfo *pixel,ExceptionInfo *exception)
2282 id = GetOpenMPThreadId();
2284 register const Quantum
2287 assert(image != (const Image *) NULL);
2288 assert(image->signature == MagickSignature);
2289 assert(image->cache != (Cache) NULL);
2290 cache_info=(CacheInfo *) image->cache;
2291 assert(cache_info->signature == MagickSignature);
2292 assert(id < (int) cache_info->number_threads);
2293 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2294 cache_info->nexus_info[id],exception);
2295 GetPixelInfo(image,pixel);
2296 if (p == (const Quantum *) NULL)
2297 return(MagickFalse);
2298 GetPixelInfoPixel(image,p,pixel);
2303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2307 % G e t O n e V i r t u a l P i x e l %
2311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2313 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2314 % (x,y) location. The image background color is returned if an error occurs.
2315 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2317 % The format of the GetOneVirtualPixel() method is:
2319 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2320 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2322 % A description of each parameter follows:
2324 % o image: the image.
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 GetOneVirtualPixel(const Image *image,
2334 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2340 id = GetOpenMPThreadId();
2348 assert(image != (const Image *) NULL);
2349 assert(image->signature == MagickSignature);
2350 assert(image->cache != (Cache) NULL);
2351 cache_info=(CacheInfo *) image->cache;
2352 assert(cache_info->signature == MagickSignature);
2353 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2354 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2355 (GetOneVirtualPixelFromHandler) NULL)
2356 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2357 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2358 assert(id < (int) cache_info->number_threads);
2359 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2360 1UL,1UL,cache_info->nexus_info[id],exception);
2361 if (p == (const Quantum *) NULL)
2363 pixel[RedPixelChannel]=image->background_color.red;
2364 pixel[GreenPixelChannel]=image->background_color.green;
2365 pixel[BluePixelChannel]=image->background_color.blue;
2366 pixel[BlackPixelChannel]=image->background_color.black;
2367 pixel[AlphaPixelChannel]=image->background_color.alpha;
2368 return(MagickFalse);
2370 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2375 channel=GetPixelChannelMapChannel(image,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 F r o m C a c h e %
2390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2392 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2393 % specified (x,y) location. The image background color is returned if an
2396 % The format of the GetOneVirtualPixelFromCache() method is:
2398 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2399 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2400 % Quantum *pixel,ExceptionInfo *exception)
2402 % A description of each parameter follows:
2404 % o image: the image.
2406 % o virtual_pixel_method: the virtual pixel method.
2408 % o x,y: These values define the location of the pixel to return.
2410 % o pixel: return a pixel at the specified (x,y) location.
2412 % o exception: return any errors or warnings in this structure.
2415 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2416 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2417 Quantum *pixel,ExceptionInfo *exception)
2423 id = GetOpenMPThreadId();
2431 assert(image != (const Image *) NULL);
2432 assert(image->signature == MagickSignature);
2433 assert(image->cache != (Cache) NULL);
2434 cache_info=(CacheInfo *) image->cache;
2435 assert(cache_info->signature == MagickSignature);
2436 assert(id < (int) cache_info->number_threads);
2437 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2439 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[BlackPixelChannel]=image->background_color.black;
2446 pixel[AlphaPixelChannel]=image->background_color.alpha;
2447 return(MagickFalse);
2449 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2454 channel=GetPixelChannelMapChannel(image,i);
2455 pixel[channel]=p[i];
2461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465 + G e t P i x e l C a c h e C o l o r s p a c e %
2469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2471 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2473 % The format of the GetPixelCacheColorspace() method is:
2475 % Colorspace GetPixelCacheColorspace(Cache cache)
2477 % A description of each parameter follows:
2479 % o cache: the pixel cache.
2482 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2487 assert(cache != (Cache) NULL);
2488 cache_info=(CacheInfo *) cache;
2489 assert(cache_info->signature == MagickSignature);
2490 if (cache_info->debug != MagickFalse)
2491 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2492 cache_info->filename);
2493 return(cache_info->colorspace);
2497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501 + G e t P i x e l C a c h e M e t h o d s %
2505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2507 % GetPixelCacheMethods() initializes the CacheMethods structure.
2509 % The format of the GetPixelCacheMethods() method is:
2511 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2513 % A description of each parameter follows:
2515 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2518 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2520 assert(cache_methods != (CacheMethods *) NULL);
2521 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2522 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2523 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2524 cache_methods->get_virtual_metacontent_from_handler=
2525 GetVirtualMetacontentFromCache;
2526 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2527 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2528 cache_methods->get_authentic_metacontent_from_handler=
2529 GetAuthenticMetacontentFromCache;
2530 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2531 cache_methods->get_one_authentic_pixel_from_handler=
2532 GetOneAuthenticPixelFromCache;
2533 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2534 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2535 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2543 + G e t P i x e l C a c h e N e x u s E x t e n t %
2547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2549 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2550 % corresponding with the last call to SetPixelCacheNexusPixels() or
2551 % GetPixelCacheNexusPixels().
2553 % The format of the GetPixelCacheNexusExtent() method is:
2555 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2556 % NexusInfo *nexus_info)
2558 % A description of each parameter follows:
2560 % o nexus_info: the nexus info.
2563 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2564 NexusInfo *nexus_info)
2572 assert(cache != NULL);
2573 cache_info=(CacheInfo *) cache;
2574 assert(cache_info->signature == MagickSignature);
2575 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2577 return((MagickSizeType) cache_info->columns*cache_info->rows);
2582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2586 + 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 %
2590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2592 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2595 % The format of the GetPixelCacheNexusMetacontent() method is:
2597 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2598 % NexusInfo *nexus_info)
2600 % A description of each parameter follows:
2602 % o cache: the pixel cache.
2604 % o nexus_info: the cache nexus to return the meta-content.
2607 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2608 NexusInfo *nexus_info)
2613 assert(cache != NULL);
2614 cache_info=(CacheInfo *) cache;
2615 assert(cache_info->signature == MagickSignature);
2616 if (cache_info->storage_class == UndefinedClass)
2617 return((void *) NULL);
2618 return(nexus_info->metacontent);
2622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2626 + G e t P i x e l C a c h e N e x u s P i x e l s %
2630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2632 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2635 % The format of the GetPixelCacheNexusPixels() method is:
2637 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2638 % NexusInfo *nexus_info)
2640 % A description of each parameter follows:
2642 % o cache: the pixel cache.
2644 % o nexus_info: the cache nexus to return the pixels.
2647 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2648 NexusInfo *nexus_info)
2653 assert(cache != NULL);
2654 cache_info=(CacheInfo *) cache;
2655 assert(cache_info->signature == MagickSignature);
2656 if (cache_info->storage_class == UndefinedClass)
2657 return((Quantum *) NULL);
2658 return(nexus_info->pixels);
2662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2666 + G e t P i x e l C a c h e P i x e l s %
2670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2672 % GetPixelCachePixels() returns the pixels associated with the specified image.
2674 % The format of the GetPixelCachePixels() method is:
2676 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2677 % ExceptionInfo *exception)
2679 % A description of each parameter follows:
2681 % o image: the image.
2683 % o length: the pixel cache length.
2685 % o exception: return any errors or warnings in this structure.
2688 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2689 ExceptionInfo *exception)
2694 assert(image != (const Image *) NULL);
2695 assert(image->signature == MagickSignature);
2696 assert(image->cache != (Cache) NULL);
2697 assert(length != (MagickSizeType *) NULL);
2698 assert(exception != (ExceptionInfo *) NULL);
2699 assert(exception->signature == MagickSignature);
2700 cache_info=(CacheInfo *) image->cache;
2701 assert(cache_info->signature == MagickSignature);
2703 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2704 return((void *) NULL);
2705 *length=cache_info->length;
2706 return((void *) cache_info->pixels);
2710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2714 + 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 %
2718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2720 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2722 % The format of the GetPixelCacheStorageClass() method is:
2724 % ClassType GetPixelCacheStorageClass(Cache cache)
2726 % A description of each parameter follows:
2728 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2730 % o cache: the pixel cache.
2733 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2738 assert(cache != (Cache) NULL);
2739 cache_info=(CacheInfo *) cache;
2740 assert(cache_info->signature == MagickSignature);
2741 if (cache_info->debug != MagickFalse)
2742 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2743 cache_info->filename);
2744 return(cache_info->storage_class);
2748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2752 + G e t P i x e l C a c h e T i l e S i z e %
2756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2758 % GetPixelCacheTileSize() returns the pixel cache tile size.
2760 % The format of the GetPixelCacheTileSize() method is:
2762 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2765 % A description of each parameter follows:
2767 % o image: the image.
2769 % o width: the optimize cache tile width in pixels.
2771 % o height: the optimize cache tile height in pixels.
2774 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2780 assert(image != (Image *) NULL);
2781 assert(image->signature == MagickSignature);
2782 if (image->debug != MagickFalse)
2783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2784 cache_info=(CacheInfo *) image->cache;
2785 assert(cache_info->signature == MagickSignature);
2786 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2787 if (GetPixelCacheType(image) == DiskCache)
2788 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2797 + G e t P i x e l C a c h e T y p e %
2801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2803 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2805 % The format of the GetPixelCacheType() method is:
2807 % CacheType GetPixelCacheType(const Image *image)
2809 % A description of each parameter follows:
2811 % o image: the image.
2814 MagickPrivate CacheType GetPixelCacheType(const Image *image)
2819 assert(image != (Image *) NULL);
2820 assert(image->signature == MagickSignature);
2821 assert(image->cache != (Cache) NULL);
2822 cache_info=(CacheInfo *) image->cache;
2823 assert(cache_info->signature == MagickSignature);
2824 return(cache_info->type);
2828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2832 + 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 %
2836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2838 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2839 % pixel cache. A virtual pixel is any pixel access that is outside the
2840 % boundaries of the image cache.
2842 % The format of the GetPixelCacheVirtualMethod() method is:
2844 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2846 % A description of each parameter follows:
2848 % o image: the image.
2851 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2856 assert(image != (Image *) NULL);
2857 assert(image->signature == MagickSignature);
2858 assert(image->cache != (Cache) NULL);
2859 cache_info=(CacheInfo *) image->cache;
2860 assert(cache_info->signature == MagickSignature);
2861 return(cache_info->virtual_pixel_method);
2865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2869 + 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 %
2873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2875 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2876 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2878 % The format of the GetVirtualMetacontentFromCache() method is:
2880 % void *GetVirtualMetacontentFromCache(const Image *image)
2882 % A description of each parameter follows:
2884 % o image: the image.
2887 static const void *GetVirtualMetacontentFromCache(const Image *image)
2893 id = GetOpenMPThreadId();
2898 assert(image != (const Image *) NULL);
2899 assert(image->signature == MagickSignature);
2900 assert(image->cache != (Cache) NULL);
2901 cache_info=(CacheInfo *) image->cache;
2902 assert(cache_info->signature == MagickSignature);
2903 assert(id < (int) cache_info->number_threads);
2904 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2905 cache_info->nexus_info[id]);
2906 return(metacontent);
2910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2914 + 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 %
2918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2920 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2923 % The format of the GetVirtualMetacontentFromNexus() method is:
2925 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2926 % NexusInfo *nexus_info)
2928 % A description of each parameter follows:
2930 % o cache: the pixel cache.
2932 % o nexus_info: the cache nexus to return the meta-content.
2935 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2936 NexusInfo *nexus_info)
2941 assert(cache != (Cache) NULL);
2942 cache_info=(CacheInfo *) cache;
2943 assert(cache_info->signature == MagickSignature);
2944 if (cache_info->storage_class == UndefinedClass)
2945 return((void *) NULL);
2946 return(nexus_info->metacontent);
2950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2954 % G e t V i r t u a l M e t a c o n t e n t %
2958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2960 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2961 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2962 % returned if the meta-content are not available.
2964 % The format of the GetVirtualMetacontent() method is:
2966 % const void *GetVirtualMetacontent(const Image *image)
2968 % A description of each parameter follows:
2970 % o image: the image.
2973 MagickExport const void *GetVirtualMetacontent(const Image *image)
2979 id = GetOpenMPThreadId();
2984 assert(image != (const Image *) NULL);
2985 assert(image->signature == MagickSignature);
2986 assert(image->cache != (Cache) NULL);
2987 cache_info=(CacheInfo *) image->cache;
2988 assert(cache_info->signature == MagickSignature);
2989 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2990 (GetVirtualMetacontentFromHandler) NULL)
2992 metacontent=cache_info->methods.
2993 get_virtual_metacontent_from_handler(image);
2994 return(metacontent);
2996 assert(id < (int) cache_info->number_threads);
2997 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2998 cache_info->nexus_info[id]);
2999 return(metacontent);
3003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007 + 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 %
3011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3013 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3014 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3015 % is returned if the pixels are transferred, otherwise a NULL is returned.
3017 % The format of the GetVirtualPixelsFromNexus() method is:
3019 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
3020 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3021 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
3022 % ExceptionInfo *exception)
3024 % A description of each parameter follows:
3026 % o image: the image.
3028 % o virtual_pixel_method: the virtual pixel method.
3030 % o x,y,columns,rows: These values define the perimeter of a region of
3033 % o nexus_info: the cache nexus to acquire.
3035 % o exception: return any errors or warnings in this structure.
3042 0, 48, 12, 60, 3, 51, 15, 63,
3043 32, 16, 44, 28, 35, 19, 47, 31,
3044 8, 56, 4, 52, 11, 59, 7, 55,
3045 40, 24, 36, 20, 43, 27, 39, 23,
3046 2, 50, 14, 62, 1, 49, 13, 61,
3047 34, 18, 46, 30, 33, 17, 45, 29,
3048 10, 58, 6, 54, 9, 57, 5, 53,
3049 42, 26, 38, 22, 41, 25, 37, 21
3052 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3057 index=x+DitherMatrix[x & 0x07]-32L;
3060 if (index >= (ssize_t) columns)
3061 return((ssize_t) columns-1L);
3065 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3070 index=y+DitherMatrix[y & 0x07]-32L;
3073 if (index >= (ssize_t) rows)
3074 return((ssize_t) rows-1L);
3078 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3082 if (x >= (ssize_t) columns)
3083 return((ssize_t) (columns-1));
3087 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3091 if (y >= (ssize_t) rows)
3092 return((ssize_t) (rows-1));
3096 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3098 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3101 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3103 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3106 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3107 const size_t extent)
3113 Compute the remainder of dividing offset by extent. It returns not only
3114 the quotient (tile the offset falls in) but also the positive remainer
3115 within that tile such that 0 <= remainder < extent. This method is
3116 essentially a ldiv() using a floored modulo division rather than the
3117 normal default truncated modulo division.
3119 modulo.quotient=offset/(ssize_t) extent;
3122 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3126 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3127 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3128 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3129 ExceptionInfo *exception)
3146 virtual_pixel[CompositePixelChannel];
3151 register const Quantum
3164 register unsigned char
3171 *virtual_metacontent;
3176 assert(image != (const Image *) NULL);
3177 assert(image->signature == MagickSignature);
3178 assert(image->cache != (Cache) NULL);
3179 cache_info=(CacheInfo *) image->cache;
3180 assert(cache_info->signature == MagickSignature);
3181 if (cache_info->type == UndefinedCache)
3182 return((const Quantum *) NULL);
3185 region.width=columns;
3187 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3188 if (pixels == (Quantum *) NULL)
3189 return((const Quantum *) NULL);
3191 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3192 nexus_info->region.x;
3193 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3194 nexus_info->region.width-1L;
3195 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3196 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3197 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3198 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3204 Pixel request is inside cache extents.
3206 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3208 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3209 if (status == MagickFalse)
3210 return((const Quantum *) NULL);
3211 if (cache_info->metacontent_extent != 0)
3213 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3214 if (status == MagickFalse)
3215 return((const Quantum *) NULL);
3220 Pixel request is outside cache extents.
3222 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3223 virtual_nexus=AcquirePixelCacheNexus(1);
3224 if (virtual_nexus == (NexusInfo **) NULL)
3226 if (virtual_nexus != (NexusInfo **) NULL)
3227 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3228 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3229 "UnableToGetCacheNexus","`%s'",image->filename);
3230 return((const Quantum *) NULL);
3232 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3233 sizeof(*virtual_pixel));
3234 virtual_metacontent=(void *) NULL;
3235 switch (virtual_pixel_method)
3237 case BackgroundVirtualPixelMethod:
3238 case BlackVirtualPixelMethod:
3239 case GrayVirtualPixelMethod:
3240 case TransparentVirtualPixelMethod:
3241 case MaskVirtualPixelMethod:
3242 case WhiteVirtualPixelMethod:
3243 case EdgeVirtualPixelMethod:
3244 case CheckerTileVirtualPixelMethod:
3245 case HorizontalTileVirtualPixelMethod:
3246 case VerticalTileVirtualPixelMethod:
3248 if (cache_info->metacontent_extent != 0)
3251 Acquire a metacontent buffer.
3253 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3254 cache_info->metacontent_extent);
3255 if (virtual_metacontent == (void *) NULL)
3257 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3258 (void) ThrowMagickException(exception,GetMagickModule(),
3259 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3260 return((const Quantum *) NULL);
3262 (void) ResetMagickMemory(virtual_metacontent,0,
3263 cache_info->metacontent_extent);
3265 switch (virtual_pixel_method)
3267 case BlackVirtualPixelMethod:
3269 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3270 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3271 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3274 case GrayVirtualPixelMethod:
3276 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3277 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3279 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3282 case TransparentVirtualPixelMethod:
3284 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3285 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3286 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3289 case MaskVirtualPixelMethod:
3290 case WhiteVirtualPixelMethod:
3292 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3293 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3294 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3299 SetPixelRed(image,image->background_color.red,virtual_pixel);
3300 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3301 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
3302 if (image->colorspace == CMYKColorspace)
3303 SetPixelBlack(image,image->background_color.black,virtual_pixel);
3304 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3313 for (v=0; v < (ssize_t) rows; v++)
3315 for (u=0; u < (ssize_t) columns; u+=length)
3317 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3318 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3319 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3327 Transfer a single pixel.
3329 length=(MagickSizeType) 1;
3330 switch (virtual_pixel_method)
3334 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3335 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3336 1UL,1UL,*virtual_nexus,exception);
3337 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3340 case RandomVirtualPixelMethod:
3342 if (cache_info->random_info == (RandomInfo *) NULL)
3343 cache_info->random_info=AcquireRandomInfo();
3344 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3345 RandomX(cache_info->random_info,cache_info->columns),
3346 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3347 *virtual_nexus,exception);
3348 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3351 case DitherVirtualPixelMethod:
3353 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3354 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3355 1UL,1UL,*virtual_nexus,exception);
3356 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3359 case TileVirtualPixelMethod:
3361 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3362 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3363 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3364 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3366 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3369 case MirrorVirtualPixelMethod:
3371 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3372 if ((x_modulo.quotient & 0x01) == 1L)
3373 x_modulo.remainder=(ssize_t) cache_info->columns-
3374 x_modulo.remainder-1L;
3375 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3376 if ((y_modulo.quotient & 0x01) == 1L)
3377 y_modulo.remainder=(ssize_t) cache_info->rows-
3378 y_modulo.remainder-1L;
3379 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3380 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3382 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3385 case HorizontalTileEdgeVirtualPixelMethod:
3387 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3388 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3389 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3390 *virtual_nexus,exception);
3391 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3394 case VerticalTileEdgeVirtualPixelMethod:
3396 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3397 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3398 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3399 *virtual_nexus,exception);
3400 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3403 case BackgroundVirtualPixelMethod:
3404 case BlackVirtualPixelMethod:
3405 case GrayVirtualPixelMethod:
3406 case TransparentVirtualPixelMethod:
3407 case MaskVirtualPixelMethod:
3408 case WhiteVirtualPixelMethod:
3411 r=virtual_metacontent;
3414 case EdgeVirtualPixelMethod:
3415 case CheckerTileVirtualPixelMethod:
3417 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3418 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3419 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3422 r=virtual_metacontent;
3425 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3426 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3428 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3431 case HorizontalTileVirtualPixelMethod:
3433 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3436 r=virtual_metacontent;
3439 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3440 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3441 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3442 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3444 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3447 case VerticalTileVirtualPixelMethod:
3449 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3452 r=virtual_metacontent;
3455 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3456 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3457 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3458 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3460 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3464 if (p == (const Quantum *) NULL)
3466 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3468 q+=cache_info->number_channels;
3469 if ((s != (void *) NULL) && (r != (const void *) NULL))
3471 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3472 s+=cache_info->metacontent_extent;
3477 Transfer a run of pixels.
3479 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3480 length,1UL,*virtual_nexus,exception);
3481 if (p == (const Quantum *) NULL)
3483 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3484 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3485 q+=length*cache_info->number_channels;
3486 if ((r != (void *) NULL) && (s != (const void *) NULL))
3488 (void) memcpy(s,r,(size_t) length);
3489 s+=length*cache_info->metacontent_extent;
3496 if (virtual_metacontent != (void *) NULL)
3497 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3498 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3507 + G e t V i r t u a l P i x e l C a c h e %
3511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3513 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3514 % cache as defined by the geometry parameters. A pointer to the pixels
3515 % is returned if the pixels are transferred, otherwise a NULL is returned.
3517 % The format of the GetVirtualPixelCache() method is:
3519 % const Quantum *GetVirtualPixelCache(const Image *image,
3520 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3521 % const ssize_t y,const size_t columns,const size_t rows,
3522 % ExceptionInfo *exception)
3524 % A description of each parameter follows:
3526 % o image: the image.
3528 % o virtual_pixel_method: the virtual pixel method.
3530 % o x,y,columns,rows: These values define the perimeter of a region of
3533 % o exception: return any errors or warnings in this structure.
3536 static const Quantum *GetVirtualPixelCache(const Image *image,
3537 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3538 const size_t columns,const size_t rows,ExceptionInfo *exception)
3544 id = GetOpenMPThreadId();
3549 assert(image != (const Image *) NULL);
3550 assert(image->signature == MagickSignature);
3551 assert(image->cache != (Cache) NULL);
3552 cache_info=(CacheInfo *) image->cache;
3553 assert(cache_info->signature == MagickSignature);
3554 assert(id < (int) cache_info->number_threads);
3555 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3556 cache_info->nexus_info[id],exception);
3561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3565 % G e t V i r t u a l P i x e l Q u e u e %
3569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3571 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3572 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3574 % The format of the GetVirtualPixelQueue() method is:
3576 % const Quantum *GetVirtualPixelQueue(const Image image)
3578 % A description of each parameter follows:
3580 % o image: the image.
3583 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3589 id = GetOpenMPThreadId();
3591 assert(image != (const Image *) NULL);
3592 assert(image->signature == MagickSignature);
3593 assert(image->cache != (Cache) NULL);
3594 cache_info=(CacheInfo *) image->cache;
3595 assert(cache_info->signature == MagickSignature);
3596 if (cache_info->methods.get_virtual_pixels_handler !=
3597 (GetVirtualPixelsHandler) NULL)
3598 return(cache_info->methods.get_virtual_pixels_handler(image));
3599 assert(id < (int) cache_info->number_threads);
3600 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3608 % G e t V i r t u a l P i x e l s %
3612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614 % GetVirtualPixels() returns an immutable pixel region. If the
3615 % region is successfully accessed, a pointer to it is returned, otherwise
3616 % NULL is returned. The returned pointer may point to a temporary working
3617 % copy of the pixels or it may point to the original pixels in memory.
3618 % Performance is maximized if the selected region is part of one row, or one
3619 % or more full rows, since there is opportunity to access the pixels in-place
3620 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3621 % returned pointer must *never* be deallocated by the user.
3623 % Pixels accessed via the returned pointer represent a simple array of type
3624 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3625 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3626 % access the meta-content (of type void) corresponding to the the
3629 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3631 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3632 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3633 % GetCacheViewAuthenticPixels() instead.
3635 % The format of the GetVirtualPixels() method is:
3637 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3638 % const ssize_t y,const size_t columns,const size_t rows,
3639 % ExceptionInfo *exception)
3641 % A description of each parameter follows:
3643 % o image: the image.
3645 % o x,y,columns,rows: These values define the perimeter of a region of
3648 % o exception: return any errors or warnings in this structure.
3651 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3652 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3653 ExceptionInfo *exception)
3659 id = GetOpenMPThreadId();
3664 assert(image != (const Image *) NULL);
3665 assert(image->signature == MagickSignature);
3666 assert(image->cache != (Cache) NULL);
3667 cache_info=(CacheInfo *) image->cache;
3668 assert(cache_info->signature == MagickSignature);
3669 if (cache_info->methods.get_virtual_pixel_handler !=
3670 (GetVirtualPixelHandler) NULL)
3671 return(cache_info->methods.get_virtual_pixel_handler(image,
3672 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3673 assert(id < (int) cache_info->number_threads);
3674 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3675 columns,rows,cache_info->nexus_info[id],exception);
3680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3684 + 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 %
3688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3690 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3691 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3693 % The format of the GetVirtualPixelsCache() method is:
3695 % Quantum *GetVirtualPixelsCache(const Image *image)
3697 % A description of each parameter follows:
3699 % o image: the image.
3702 static const Quantum *GetVirtualPixelsCache(const Image *image)
3708 id = GetOpenMPThreadId();
3710 assert(image != (const Image *) NULL);
3711 assert(image->signature == MagickSignature);
3712 assert(image->cache != (Cache) NULL);
3713 cache_info=(CacheInfo *) image->cache;
3714 assert(cache_info->signature == MagickSignature);
3715 assert(id < (int) cache_info->number_threads);
3716 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3724 + G e t V i r t u a l P i x e l s N e x u s %
3728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3730 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3733 % The format of the GetVirtualPixelsNexus() method is:
3735 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3736 % NexusInfo *nexus_info)
3738 % A description of each parameter follows:
3740 % o cache: the pixel cache.
3742 % o nexus_info: the cache nexus to return the colormap pixels.
3745 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3746 NexusInfo *nexus_info)
3751 assert(cache != (Cache) NULL);
3752 cache_info=(CacheInfo *) cache;
3753 assert(cache_info->signature == MagickSignature);
3754 if (cache_info->storage_class == UndefinedClass)
3755 return((Quantum *) NULL);
3756 return((const Quantum *) nexus_info->pixels);
3760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3764 + M a s k P i x e l C a c h e N e x u s %
3768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3770 % MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3771 % The method returns MagickTrue if the pixel region is masked, otherwise
3774 % The format of the MaskPixelCacheNexus() method is:
3776 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3777 % NexusInfo *nexus_info,ExceptionInfo *exception)
3779 % A description of each parameter follows:
3781 % o image: the image.
3783 % o nexus_info: the cache nexus to clip.
3785 % o exception: return any errors or warnings in this structure.
3789 static inline void MagickPixelCompositeMask(const PixelInfo *p,
3790 const MagickRealType alpha,const PixelInfo *q,
3791 const MagickRealType beta,PixelInfo *composite)
3796 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
3801 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3802 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3803 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3804 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3805 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3806 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3807 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
3810 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3811 ExceptionInfo *exception)
3827 register const Quantum
3840 if (image->debug != MagickFalse)
3841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3842 if (image->mask == (Image *) NULL)
3843 return(MagickFalse);
3844 cache_info=(CacheInfo *) image->cache;
3845 if (cache_info == (Cache) NULL)
3846 return(MagickFalse);
3847 image_nexus=AcquirePixelCacheNexus(1);
3848 clip_nexus=AcquirePixelCacheNexus(1);
3849 if ((image_nexus == (NexusInfo **) NULL) ||
3850 (clip_nexus == (NexusInfo **) NULL))
3851 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3852 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3853 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3854 nexus_info->region.height,image_nexus[0],exception);
3855 q=nexus_info->pixels;
3856 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3857 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3858 nexus_info->region.height,clip_nexus[0],exception);
3859 GetPixelInfo(image,&alpha);
3860 GetPixelInfo(image,&beta);
3861 number_pixels=(MagickSizeType) nexus_info->region.width*
3862 nexus_info->region.height;
3863 for (i=0; i < (ssize_t) number_pixels; i++)
3865 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
3867 GetPixelInfoPixel(image,p,&alpha);
3868 GetPixelInfoPixel(image,q,&beta);
3869 MagickPixelCompositeMask(&beta,(MagickRealType) GetPixelIntensity(image,r),
3870 &alpha,alpha.alpha,&beta);
3871 SetPixelRed(image,ClampToQuantum(beta.red),q);
3872 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3873 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3874 if (cache_info->colorspace == CMYKColorspace)
3875 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3876 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
3881 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3882 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3883 if (i < (ssize_t) number_pixels)
3884 return(MagickFalse);
3889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3893 + O p e n P i x e l C a c h e %
3897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3899 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3900 % dimensions, allocating space for the image pixels and optionally the
3901 % metacontent, and memory mapping the cache if it is disk based. The cache
3902 % nexus array is initialized as well.
3904 % The format of the OpenPixelCache() method is:
3906 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3907 % ExceptionInfo *exception)
3909 % A description of each parameter follows:
3911 % o image: the image.
3913 % o mode: ReadMode, WriteMode, or IOMode.
3915 % o exception: return any errors or warnings in this structure.
3919 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3921 cache_info->mapped=MagickFalse;
3922 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3923 cache_info->length);
3924 if (cache_info->pixels == (Quantum *) NULL)
3926 cache_info->mapped=MagickTrue;
3927 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3928 cache_info->length);
3932 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3942 cache_info=(CacheInfo *) image->cache;
3943 if (image->debug != MagickFalse)
3946 format[MaxTextExtent],
3947 message[MaxTextExtent];
3949 (void) FormatMagickSize(length,MagickFalse,format);
3950 (void) FormatLocaleString(message,MaxTextExtent,
3951 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3952 cache_info->cache_filename,cache_info->file,format);
3953 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3955 if (length != (MagickSizeType) ((MagickOffsetType) length))
3956 return(MagickFalse);
3957 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3959 return(MagickFalse);
3960 if ((MagickSizeType) extent >= length)
3962 offset=(MagickOffsetType) length-1;
3963 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3964 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3967 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3968 ExceptionInfo *exception)
3975 format[MaxTextExtent],
3976 message[MaxTextExtent];
3989 assert(image != (const Image *) NULL);
3990 assert(image->signature == MagickSignature);
3991 assert(image->cache != (Cache) NULL);
3992 if (image->debug != MagickFalse)
3993 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3994 if ((image->columns == 0) || (image->rows == 0))
3995 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3996 cache_info=(CacheInfo *) image->cache;
3997 assert(cache_info->signature == MagickSignature);
3998 source_info=(*cache_info);
3999 source_info.file=(-1);
4000 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4001 image->filename,(double) GetImageIndexInList(image));
4002 cache_info->storage_class=image->storage_class;
4003 cache_info->colorspace=image->colorspace;
4004 cache_info->matte=image->matte;
4005 cache_info->rows=image->rows;
4006 cache_info->columns=image->columns;
4007 InitializePixelChannelMap(image);
4008 cache_info->number_channels=GetPixelChannels(image);
4009 cache_info->metacontent_extent=image->metacontent_extent;
4010 cache_info->mode=mode;
4011 if (image->ping != MagickFalse)
4013 cache_info->type=PingCache;
4014 cache_info->pixels=(Quantum *) NULL;
4015 cache_info->metacontent=(void *) NULL;
4016 cache_info->length=0;
4019 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4020 packet_size=cache_info->number_channels*sizeof(Quantum);
4021 if (image->metacontent_extent != 0)
4022 packet_size+=cache_info->metacontent_extent;
4023 length=number_pixels*packet_size;
4024 columns=(size_t) (length/cache_info->rows/packet_size);
4025 if (cache_info->columns != columns)
4026 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4028 cache_info->length=length;
4029 if ((cache_info->type != UndefinedCache) &&
4030 (cache_info->columns <= source_info.columns) &&
4031 (cache_info->rows <= source_info.rows) &&
4032 (cache_info->number_channels <= source_info.number_channels) &&
4033 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4036 Inline pixel cache clone optimization.
4038 if ((cache_info->columns == source_info.columns) &&
4039 (cache_info->rows == source_info.rows) &&
4040 (cache_info->number_channels == source_info.number_channels) &&
4041 (cache_info->metacontent_extent == source_info.metacontent_extent))
4043 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4045 status=AcquireMagickResource(AreaResource,cache_info->length);
4046 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4047 cache_info->metacontent_extent);
4048 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4050 status=AcquireMagickResource(MemoryResource,cache_info->length);
4051 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4052 (cache_info->type == MemoryCache))
4054 AllocatePixelCachePixels(cache_info);
4055 if (cache_info->pixels == (Quantum *) NULL)
4056 cache_info->pixels=source_info.pixels;
4060 Create memory pixel cache.
4063 if (image->debug != MagickFalse)
4065 (void) FormatMagickSize(cache_info->length,MagickTrue,
4067 (void) FormatLocaleString(message,MaxTextExtent,
4068 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4069 cache_info->filename,cache_info->mapped != MagickFalse ?
4070 "anonymous" : "heap",(double) cache_info->columns,(double)
4071 cache_info->rows,(double) cache_info->number_channels,
4073 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4076 cache_info->type=MemoryCache;
4077 cache_info->metacontent=(void *) NULL;
4078 if (cache_info->metacontent_extent != 0)
4079 cache_info->metacontent=(void *) (cache_info->pixels+
4080 number_pixels*cache_info->number_channels);
4081 if (source_info.storage_class != UndefinedClass)
4083 status=ClonePixelCachePixels(cache_info,&source_info,
4085 RelinquishPixelCachePixels(&source_info);
4090 RelinquishMagickResource(MemoryResource,cache_info->length);
4093 Create pixel cache on disk.
4095 status=AcquireMagickResource(DiskResource,cache_info->length);
4096 if (status == MagickFalse)
4098 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4099 "CacheResourcesExhausted","`%s'",image->filename);
4100 return(MagickFalse);
4102 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4104 RelinquishMagickResource(DiskResource,cache_info->length);
4105 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4107 return(MagickFalse);
4109 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4110 cache_info->length);
4111 if (status == MagickFalse)
4113 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4115 return(MagickFalse);
4117 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4118 cache_info->metacontent_extent);
4119 if (length != (MagickSizeType) ((size_t) length))
4120 cache_info->type=DiskCache;
4123 status=AcquireMagickResource(MapResource,cache_info->length);
4124 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4125 (cache_info->type != MemoryCache))
4126 cache_info->type=DiskCache;
4129 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4130 cache_info->offset,(size_t) cache_info->length);
4131 if (cache_info->pixels == (Quantum *) NULL)
4133 cache_info->type=DiskCache;
4134 cache_info->pixels=source_info.pixels;
4139 Create file-backed memory-mapped pixel cache.
4142 (void) ClosePixelCacheOnDisk(cache_info);
4143 cache_info->type=MapCache;
4144 cache_info->mapped=MagickTrue;
4145 cache_info->metacontent=(void *) NULL;
4146 if (cache_info->metacontent_extent != 0)
4147 cache_info->metacontent=(void *) (cache_info->pixels+
4148 number_pixels*cache_info->number_channels);
4149 if (source_info.storage_class != UndefinedClass)
4151 status=ClonePixelCachePixels(cache_info,&source_info,
4153 RelinquishPixelCachePixels(&source_info);
4155 if (image->debug != MagickFalse)
4157 (void) FormatMagickSize(cache_info->length,MagickTrue,
4159 (void) FormatLocaleString(message,MaxTextExtent,
4160 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4161 cache_info->filename,cache_info->cache_filename,
4162 cache_info->file,(double) cache_info->columns,(double)
4163 cache_info->rows,(double) cache_info->number_channels,
4165 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4171 RelinquishMagickResource(MapResource,cache_info->length);
4174 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4176 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4177 RelinquishPixelCachePixels(&source_info);
4179 if (image->debug != MagickFalse)
4181 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4182 (void) FormatLocaleString(message,MaxTextExtent,
4183 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4184 cache_info->cache_filename,cache_info->file,(double)
4185 cache_info->columns,(double) cache_info->rows,(double)
4186 cache_info->number_channels,format);
4187 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4197 + P e r s i s t P i x e l C a c h e %
4201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4203 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4204 % persistent pixel cache is one that resides on disk and is not destroyed
4205 % when the program exits.
4207 % The format of the PersistPixelCache() method is:
4209 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4210 % const MagickBooleanType attach,MagickOffsetType *offset,
4211 % ExceptionInfo *exception)
4213 % A description of each parameter follows:
4215 % o image: the image.
4217 % o filename: the persistent pixel cache filename.
4219 % o attach: A value other than zero initializes the persistent pixel cache.
4221 % o initialize: A value other than zero initializes the persistent pixel
4224 % o offset: the offset in the persistent cache to store pixels.
4226 % o exception: return any errors or warnings in this structure.
4229 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4230 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4231 ExceptionInfo *exception)
4246 assert(image != (Image *) NULL);
4247 assert(image->signature == MagickSignature);
4248 if (image->debug != MagickFalse)
4249 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4250 assert(image->cache != (void *) NULL);
4251 assert(filename != (const char *) NULL);
4252 assert(offset != (MagickOffsetType *) NULL);
4253 page_size=GetMagickPageSize();
4254 cache_info=(CacheInfo *) image->cache;
4255 assert(cache_info->signature == MagickSignature);
4256 if (attach != MagickFalse)
4259 Attach existing persistent pixel cache.
4261 if (image->debug != MagickFalse)
4262 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4263 "attach persistent cache");
4264 (void) CopyMagickString(cache_info->cache_filename,filename,
4266 cache_info->type=DiskCache;
4267 cache_info->offset=(*offset);
4268 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4269 return(MagickFalse);
4270 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4273 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4274 (cache_info->reference_count == 1))
4276 LockSemaphoreInfo(cache_info->semaphore);
4277 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4278 (cache_info->reference_count == 1))
4284 Usurp existing persistent pixel cache.
4286 status=rename_utf8(cache_info->cache_filename,filename);
4289 (void) CopyMagickString(cache_info->cache_filename,filename,
4291 *offset+=cache_info->length+page_size-(cache_info->length %
4293 UnlockSemaphoreInfo(cache_info->semaphore);
4294 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4295 if (image->debug != MagickFalse)
4296 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4297 "Usurp resident persistent cache");
4301 UnlockSemaphoreInfo(cache_info->semaphore);
4304 Clone persistent pixel cache.
4306 clone_image=(*image);
4307 clone_info=(CacheInfo *) clone_image.cache;
4308 image->cache=ClonePixelCache(cache_info);
4309 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4310 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4311 cache_info->type=DiskCache;
4312 cache_info->offset=(*offset);
4313 cache_info=(CacheInfo *) image->cache;
4314 status=OpenPixelCache(image,IOMode,exception);
4315 if (status != MagickFalse)
4316 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4317 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4318 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4327 + Q u e u e A u t h e n t i c N e x u s %
4331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4333 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4334 % by the region rectangle and returns a pointer to the region. This region is
4335 % subsequently transferred from the pixel cache with
4336 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4337 % pixels are transferred, otherwise a NULL is returned.
4339 % The format of the QueueAuthenticNexus() method is:
4341 % Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4342 % const ssize_t y,const size_t columns,const size_t rows,
4343 % const MagickBooleanType clone,NexusInfo *nexus_info,
4344 % ExceptionInfo *exception)
4346 % A description of each parameter follows:
4348 % o image: the image.
4350 % o x,y,columns,rows: These values define the perimeter of a region of
4353 % o nexus_info: the cache nexus to set.
4355 % o clone: clone the pixel cache.
4357 % o exception: return any errors or warnings in this structure.
4360 MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4361 const ssize_t y,const size_t columns,const size_t rows,
4362 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4377 Validate pixel cache geometry.
4379 assert(image != (const Image *) NULL);
4380 assert(image->signature == MagickSignature);
4381 assert(image->cache != (Cache) NULL);
4382 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4383 if (cache_info == (Cache) NULL)
4384 return((Quantum *) NULL);
4385 assert(cache_info->signature == MagickSignature);
4386 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4388 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4389 "NoPixelsDefinedInCache","`%s'",image->filename);
4390 return((Quantum *) NULL);
4392 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4393 (y >= (ssize_t) cache_info->rows))
4395 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4396 "PixelsAreNotAuthentic","`%s'",image->filename);
4397 return((Quantum *) NULL);
4399 offset=(MagickOffsetType) y*cache_info->columns+x;
4401 return((Quantum *) NULL);
4402 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4403 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4404 if ((MagickSizeType) offset >= number_pixels)
4405 return((Quantum *) NULL);
4411 region.width=columns;
4413 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4421 + 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 %
4425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4427 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4428 % defined by the region rectangle and returns a pointer to the region. This
4429 % region is subsequently transferred from the pixel cache with
4430 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4431 % pixels are transferred, otherwise a NULL is returned.
4433 % The format of the QueueAuthenticPixelsCache() method is:
4435 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4436 % const ssize_t y,const size_t columns,const size_t rows,
4437 % ExceptionInfo *exception)
4439 % A description of each parameter follows:
4441 % o image: the image.
4443 % o x,y,columns,rows: These values define the perimeter of a region of
4446 % o exception: return any errors or warnings in this structure.
4449 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4450 const ssize_t y,const size_t columns,const size_t rows,
4451 ExceptionInfo *exception)
4457 id = GetOpenMPThreadId();
4462 assert(image != (const Image *) NULL);
4463 assert(image->signature == MagickSignature);
4464 assert(image->cache != (Cache) NULL);
4465 cache_info=(CacheInfo *) image->cache;
4466 assert(cache_info->signature == MagickSignature);
4467 assert(id < (int) cache_info->number_threads);
4468 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4469 cache_info->nexus_info[id],exception);
4474 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4478 % Q u e u e A u t h e n t i c P i x e l s %
4482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4484 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4485 % successfully initialized a pointer to a Quantum array representing the
4486 % region is returned, otherwise NULL is returned. The returned pointer may
4487 % point to a temporary working buffer for the pixels or it may point to the
4488 % final location of the pixels in memory.
4490 % Write-only access means that any existing pixel values corresponding to
4491 % the region are ignored. This is useful if the initial image is being
4492 % created from scratch, or if the existing pixel values are to be
4493 % completely replaced without need to refer to their pre-existing values.
4494 % The application is free to read and write the pixel buffer returned by
4495 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4496 % initialize the pixel array values. Initializing pixel array values is the
4497 % application's responsibility.
4499 % Performance is maximized if the selected region is part of one row, or
4500 % one or more full rows, since then there is opportunity to access the
4501 % pixels in-place (without a copy) if the image is in memory, or in a
4502 % memory-mapped file. The returned pointer must *never* be deallocated
4505 % Pixels accessed via the returned pointer represent a simple array of type
4506 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4507 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4508 % obtain the meta-content (of type void) corresponding to the region.
4509 % Once the Quantum (and/or Quantum) array has been updated, the
4510 % changes must be saved back to the underlying image using
4511 % SyncAuthenticPixels() or they may be lost.
4513 % The format of the QueueAuthenticPixels() method is:
4515 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4516 % const ssize_t y,const size_t columns,const size_t rows,
4517 % ExceptionInfo *exception)
4519 % A description of each parameter follows:
4521 % o image: the image.
4523 % o x,y,columns,rows: These values define the perimeter of a region of
4526 % o exception: return any errors or warnings in this structure.
4529 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4530 const ssize_t y,const size_t columns,const size_t rows,
4531 ExceptionInfo *exception)
4537 id = GetOpenMPThreadId();
4542 assert(image != (Image *) NULL);
4543 assert(image->signature == MagickSignature);
4544 assert(image->cache != (Cache) NULL);
4545 cache_info=(CacheInfo *) image->cache;
4546 assert(cache_info->signature == MagickSignature);
4547 if (cache_info->methods.queue_authentic_pixels_handler !=
4548 (QueueAuthenticPixelsHandler) NULL)
4550 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4551 columns,rows,exception);
4554 assert(id < (int) cache_info->number_threads);
4555 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4556 cache_info->nexus_info[id],exception);
4561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4565 + 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 %
4569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4571 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4574 % The format of the ReadPixelCacheMetacontent() method is:
4576 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4577 % NexusInfo *nexus_info,ExceptionInfo *exception)
4579 % A description of each parameter follows:
4581 % o cache_info: the pixel cache.
4583 % o nexus_info: the cache nexus to read the metacontent.
4585 % o exception: return any errors or warnings in this structure.
4588 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4589 NexusInfo *nexus_info,ExceptionInfo *exception)
4602 register unsigned char
4608 if (cache_info->metacontent_extent == 0)
4609 return(MagickFalse);
4610 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4612 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4613 nexus_info->region.x;
4614 length=(MagickSizeType) nexus_info->region.width*
4615 cache_info->metacontent_extent;
4616 rows=nexus_info->region.height;
4618 q=(unsigned char *) nexus_info->metacontent;
4619 switch (cache_info->type)
4624 register unsigned char
4628 Read meta-content from memory.
4630 if ((cache_info->columns == nexus_info->region.width) &&
4631 (extent == (MagickSizeType) ((size_t) extent)))
4636 p=(unsigned char *) cache_info->metacontent+offset*
4637 cache_info->metacontent_extent;
4638 for (y=0; y < (ssize_t) rows; y++)
4640 (void) memcpy(q,p,(size_t) length);
4641 p+=cache_info->metacontent_extent*cache_info->columns;
4642 q+=cache_info->metacontent_extent*nexus_info->region.width;
4649 Read meta content from disk.
4651 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4653 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4654 cache_info->cache_filename);
4655 return(MagickFalse);
4657 if ((cache_info->columns == nexus_info->region.width) &&
4658 (extent <= MagickMaxBufferExtent))
4663 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4664 for (y=0; y < (ssize_t) rows; y++)
4666 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4667 cache_info->number_channels*sizeof(Quantum)+offset*
4668 cache_info->metacontent_extent,length,(unsigned char *) q);
4669 if ((MagickSizeType) count != length)
4671 offset+=cache_info->columns;
4672 q+=cache_info->metacontent_extent*nexus_info->region.width;
4674 if (y < (ssize_t) rows)
4676 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4677 cache_info->cache_filename);
4678 return(MagickFalse);
4685 if ((cache_info->debug != MagickFalse) &&
4686 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4687 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4688 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4689 nexus_info->region.width,(double) nexus_info->region.height,(double)
4690 nexus_info->region.x,(double) nexus_info->region.y);
4695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4699 + R e a d P i x e l C a c h e P i x e l s %
4703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4705 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4708 % The format of the ReadPixelCachePixels() method is:
4710 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4711 % NexusInfo *nexus_info,ExceptionInfo *exception)
4713 % A description of each parameter follows:
4715 % o cache_info: the pixel cache.
4717 % o nexus_info: the cache nexus to read the pixels.
4719 % o exception: return any errors or warnings in this structure.
4722 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4723 NexusInfo *nexus_info,ExceptionInfo *exception)
4742 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4744 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4745 nexus_info->region.x;
4746 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4748 rows=nexus_info->region.height;
4750 q=nexus_info->pixels;
4751 switch (cache_info->type)
4760 Read pixels from memory.
4762 if ((cache_info->columns == nexus_info->region.width) &&
4763 (extent == (MagickSizeType) ((size_t) extent)))
4768 p=cache_info->pixels+offset*cache_info->number_channels;
4769 for (y=0; y < (ssize_t) rows; y++)
4771 (void) memcpy(q,p,(size_t) length);
4772 p+=cache_info->number_channels*cache_info->columns;
4773 q+=cache_info->number_channels*nexus_info->region.width;
4780 Read pixels from disk.
4782 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4784 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4785 cache_info->cache_filename);
4786 return(MagickFalse);
4788 if ((cache_info->columns == nexus_info->region.width) &&
4789 (extent <= MagickMaxBufferExtent))
4794 for (y=0; y < (ssize_t) rows; y++)
4796 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4797 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4798 if ((MagickSizeType) count != length)
4800 offset+=cache_info->columns;
4801 q+=cache_info->number_channels*nexus_info->region.width;
4803 if (y < (ssize_t) rows)
4805 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4806 cache_info->cache_filename);
4807 return(MagickFalse);
4814 if ((cache_info->debug != MagickFalse) &&
4815 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4816 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4817 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4818 nexus_info->region.width,(double) nexus_info->region.height,(double)
4819 nexus_info->region.x,(double) nexus_info->region.y);
4824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4828 + R e f e r e n c e P i x e l C a c h e %
4832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4834 % ReferencePixelCache() increments the reference count associated with the
4835 % pixel cache returning a pointer to the cache.
4837 % The format of the ReferencePixelCache method is:
4839 % Cache ReferencePixelCache(Cache cache_info)
4841 % A description of each parameter follows:
4843 % o cache_info: the pixel cache.
4846 MagickPrivate Cache ReferencePixelCache(Cache cache)
4851 assert(cache != (Cache *) NULL);
4852 cache_info=(CacheInfo *) cache;
4853 assert(cache_info->signature == MagickSignature);
4854 LockSemaphoreInfo(cache_info->semaphore);
4855 cache_info->reference_count++;
4856 UnlockSemaphoreInfo(cache_info->semaphore);
4861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4865 + S e t P i x e l C a c h e M e t h o d s %
4869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4871 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4873 % The format of the SetPixelCacheMethods() method is:
4875 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4877 % A description of each parameter follows:
4879 % o cache: the pixel cache.
4881 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4884 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4889 GetOneAuthenticPixelFromHandler
4890 get_one_authentic_pixel_from_handler;
4892 GetOneVirtualPixelFromHandler
4893 get_one_virtual_pixel_from_handler;
4896 Set cache pixel methods.
4898 assert(cache != (Cache) NULL);
4899 assert(cache_methods != (CacheMethods *) NULL);
4900 cache_info=(CacheInfo *) cache;
4901 assert(cache_info->signature == MagickSignature);
4902 if (cache_info->debug != MagickFalse)
4903 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4904 cache_info->filename);
4905 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4906 cache_info->methods.get_virtual_pixel_handler=
4907 cache_methods->get_virtual_pixel_handler;
4908 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4909 cache_info->methods.destroy_pixel_handler=
4910 cache_methods->destroy_pixel_handler;
4911 if (cache_methods->get_virtual_metacontent_from_handler !=
4912 (GetVirtualMetacontentFromHandler) NULL)
4913 cache_info->methods.get_virtual_metacontent_from_handler=
4914 cache_methods->get_virtual_metacontent_from_handler;
4915 if (cache_methods->get_authentic_pixels_handler !=
4916 (GetAuthenticPixelsHandler) NULL)
4917 cache_info->methods.get_authentic_pixels_handler=
4918 cache_methods->get_authentic_pixels_handler;
4919 if (cache_methods->queue_authentic_pixels_handler !=
4920 (QueueAuthenticPixelsHandler) NULL)
4921 cache_info->methods.queue_authentic_pixels_handler=
4922 cache_methods->queue_authentic_pixels_handler;
4923 if (cache_methods->sync_authentic_pixels_handler !=
4924 (SyncAuthenticPixelsHandler) NULL)
4925 cache_info->methods.sync_authentic_pixels_handler=
4926 cache_methods->sync_authentic_pixels_handler;
4927 if (cache_methods->get_authentic_pixels_from_handler !=
4928 (GetAuthenticPixelsFromHandler) NULL)
4929 cache_info->methods.get_authentic_pixels_from_handler=
4930 cache_methods->get_authentic_pixels_from_handler;
4931 if (cache_methods->get_authentic_metacontent_from_handler !=
4932 (GetAuthenticMetacontentFromHandler) NULL)
4933 cache_info->methods.get_authentic_metacontent_from_handler=
4934 cache_methods->get_authentic_metacontent_from_handler;
4935 get_one_virtual_pixel_from_handler=
4936 cache_info->methods.get_one_virtual_pixel_from_handler;
4937 if (get_one_virtual_pixel_from_handler !=
4938 (GetOneVirtualPixelFromHandler) NULL)
4939 cache_info->methods.get_one_virtual_pixel_from_handler=
4940 cache_methods->get_one_virtual_pixel_from_handler;
4941 get_one_authentic_pixel_from_handler=
4942 cache_methods->get_one_authentic_pixel_from_handler;
4943 if (get_one_authentic_pixel_from_handler !=
4944 (GetOneAuthenticPixelFromHandler) NULL)
4945 cache_info->methods.get_one_authentic_pixel_from_handler=
4946 cache_methods->get_one_authentic_pixel_from_handler;
4950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4954 + S e t P i x e l C a c h e N e x u s P i x e l s %
4958 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4960 % SetPixelCacheNexusPixels() defines the region of the cache for the
4961 % specified cache nexus.
4963 % The format of the SetPixelCacheNexusPixels() method is:
4965 % Quantum SetPixelCacheNexusPixels(const Image *image,
4966 % const RectangleInfo *region,NexusInfo *nexus_info,
4967 % ExceptionInfo *exception)
4969 % A description of each parameter follows:
4971 % o image: the image.
4973 % o region: A pointer to the RectangleInfo structure that defines the
4974 % region of this particular cache nexus.
4976 % o nexus_info: the cache nexus to set.
4978 % o exception: return any errors or warnings in this structure.
4982 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4983 NexusInfo *nexus_info,ExceptionInfo *exception)
4985 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4986 return(MagickFalse);
4987 nexus_info->mapped=MagickFalse;
4988 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
4989 nexus_info->length);
4990 if (nexus_info->cache == (Quantum *) NULL)
4992 nexus_info->mapped=MagickTrue;
4993 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
4994 nexus_info->length);
4996 if (nexus_info->cache == (Quantum *) NULL)
4998 (void) ThrowMagickException(exception,GetMagickModule(),
4999 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5000 cache_info->filename);
5001 return(MagickFalse);
5006 static Quantum *SetPixelCacheNexusPixels(const Image *image,
5007 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5019 cache_info=(CacheInfo *) image->cache;
5020 assert(cache_info->signature == MagickSignature);
5021 if (cache_info->type == UndefinedCache)
5022 return((Quantum *) NULL);
5023 nexus_info->region=(*region);
5024 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5025 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5031 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5032 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5033 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5034 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5035 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5036 ((nexus_info->region.width == cache_info->columns) ||
5037 ((nexus_info->region.width % cache_info->columns) == 0)))))
5043 Pixels are accessed directly from memory.
5045 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5046 nexus_info->region.x;
5047 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5049 nexus_info->metacontent=(void *) NULL;
5050 if (cache_info->metacontent_extent != 0)
5051 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5052 offset*cache_info->metacontent_extent;
5053 return(nexus_info->pixels);
5057 Pixels are stored in a cache region until they are synced to the cache.
5059 number_pixels=(MagickSizeType) nexus_info->region.width*
5060 nexus_info->region.height;
5061 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
5062 if (cache_info->metacontent_extent != 0)
5063 length+=number_pixels*cache_info->metacontent_extent;
5064 if (nexus_info->cache == (Quantum *) NULL)
5066 nexus_info->length=length;
5067 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5068 if (status == MagickFalse)
5070 nexus_info->length=0;
5071 return((Quantum *) NULL);
5075 if (nexus_info->length != length)
5077 RelinquishCacheNexusPixels(nexus_info);
5078 nexus_info->length=length;
5079 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5080 if (status == MagickFalse)
5082 nexus_info->length=0;
5083 return((Quantum *) NULL);
5086 nexus_info->pixels=nexus_info->cache;
5087 nexus_info->metacontent=(void *) NULL;
5088 if (cache_info->metacontent_extent != 0)
5089 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
5090 cache_info->number_channels);
5091 return(nexus_info->pixels);
5095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5099 % 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 %
5103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5105 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5106 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5107 % access that is outside the boundaries of the image cache.
5109 % The format of the SetPixelCacheVirtualMethod() method is:
5111 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5112 % const VirtualPixelMethod virtual_pixel_method)
5114 % A description of each parameter follows:
5116 % o image: the image.
5118 % o virtual_pixel_method: choose the type of virtual pixel.
5121 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5122 const VirtualPixelMethod virtual_pixel_method)
5130 assert(image != (Image *) NULL);
5131 assert(image->signature == MagickSignature);
5132 if (image->debug != MagickFalse)
5133 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5134 assert(image->cache != (Cache) NULL);
5135 cache_info=(CacheInfo *) image->cache;
5136 assert(cache_info->signature == MagickSignature);
5137 method=cache_info->virtual_pixel_method;
5138 cache_info->virtual_pixel_method=virtual_pixel_method;
5143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5147 + 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 %
5151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5153 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5154 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5155 % is synced, otherwise MagickFalse.
5157 % The format of the SyncAuthenticPixelCacheNexus() method is:
5159 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5160 % NexusInfo *nexus_info,ExceptionInfo *exception)
5162 % A description of each parameter follows:
5164 % o image: the image.
5166 % o nexus_info: the cache nexus to sync.
5168 % o exception: return any errors or warnings in this structure.
5171 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5172 NexusInfo *nexus_info,ExceptionInfo *exception)
5181 Transfer pixels to the cache.
5183 assert(image != (Image *) NULL);
5184 assert(image->signature == MagickSignature);
5185 if (image->cache == (Cache) NULL)
5186 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5187 cache_info=(CacheInfo *) image->cache;
5188 assert(cache_info->signature == MagickSignature);
5189 if (cache_info->type == UndefinedCache)
5190 return(MagickFalse);
5191 if ((image->clip_mask != (Image *) NULL) &&
5192 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5193 return(MagickFalse);
5194 if ((image->mask != (Image *) NULL) &&
5195 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5196 return(MagickFalse);
5197 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5199 assert(cache_info->signature == MagickSignature);
5200 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5201 if ((cache_info->metacontent_extent != 0) &&
5202 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5203 return(MagickFalse);
5208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5212 + S y n c A u t h e n t i c P i x e l C a c h e %
5216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5218 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5219 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5220 % otherwise MagickFalse.
5222 % The format of the SyncAuthenticPixelsCache() method is:
5224 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5225 % ExceptionInfo *exception)
5227 % A description of each parameter follows:
5229 % o image: the image.
5231 % o exception: return any errors or warnings in this structure.
5234 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5235 ExceptionInfo *exception)
5241 id = GetOpenMPThreadId();
5246 assert(image != (Image *) NULL);
5247 assert(image->signature == MagickSignature);
5248 assert(image->cache != (Cache) NULL);
5249 cache_info=(CacheInfo *) image->cache;
5250 assert(cache_info->signature == MagickSignature);
5251 assert(id < (int) cache_info->number_threads);
5252 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5262 % S y n c A u t h e n t i c P i x e l s %
5266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5268 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5269 % The method returns MagickTrue if the pixel region is flushed, otherwise
5272 % The format of the SyncAuthenticPixels() method is:
5274 % MagickBooleanType SyncAuthenticPixels(Image *image,
5275 % ExceptionInfo *exception)
5277 % A description of each parameter follows:
5279 % o image: the image.
5281 % o exception: return any errors or warnings in this structure.
5284 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5285 ExceptionInfo *exception)
5291 id = GetOpenMPThreadId();
5296 assert(image != (Image *) NULL);
5297 assert(image->signature == MagickSignature);
5298 assert(image->cache != (Cache) NULL);
5299 cache_info=(CacheInfo *) image->cache;
5300 assert(cache_info->signature == MagickSignature);
5301 if (cache_info->methods.sync_authentic_pixels_handler !=
5302 (SyncAuthenticPixelsHandler) NULL)
5304 status=cache_info->methods.sync_authentic_pixels_handler(image,
5308 assert(id < (int) cache_info->number_threads);
5309 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5319 + S y n c I m a g e P i x e l C a c h e %
5323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5325 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5326 % The method returns MagickTrue if the pixel region is flushed, otherwise
5329 % The format of the SyncImagePixelCache() method is:
5331 % MagickBooleanType SyncImagePixelCache(Image *image,
5332 % ExceptionInfo *exception)
5334 % A description of each parameter follows:
5336 % o image: the image.
5338 % o exception: return any errors or warnings in this structure.
5341 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5342 ExceptionInfo *exception)
5347 assert(image != (Image *) NULL);
5348 assert(exception != (ExceptionInfo *) NULL);
5349 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5350 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5358 + 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 %
5362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5364 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5365 % of the pixel cache.
5367 % The format of the WritePixelCacheMetacontent() method is:
5369 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5370 % NexusInfo *nexus_info,ExceptionInfo *exception)
5372 % A description of each parameter follows:
5374 % o cache_info: the pixel cache.
5376 % o nexus_info: the cache nexus to write the meta-content.
5378 % o exception: return any errors or warnings in this structure.
5381 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5382 NexusInfo *nexus_info,ExceptionInfo *exception)
5392 register const unsigned char
5401 if (cache_info->metacontent_extent == 0)
5402 return(MagickFalse);
5403 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5405 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5406 nexus_info->region.x;
5407 length=(MagickSizeType) nexus_info->region.width*
5408 cache_info->metacontent_extent;
5409 rows=nexus_info->region.height;
5410 extent=(MagickSizeType) length*rows;
5411 p=(unsigned char *) nexus_info->metacontent;
5412 switch (cache_info->type)
5417 register unsigned char
5421 Write associated pixels to memory.
5423 if ((cache_info->columns == nexus_info->region.width) &&
5424 (extent == (MagickSizeType) ((size_t) extent)))
5429 q=(unsigned char *) cache_info->metacontent+offset*
5430 cache_info->metacontent_extent;
5431 for (y=0; y < (ssize_t) rows; y++)
5433 (void) memcpy(q,p,(size_t) length);
5434 p+=nexus_info->region.width*cache_info->metacontent_extent;
5435 q+=cache_info->columns*cache_info->metacontent_extent;
5442 Write associated pixels to disk.
5444 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5446 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5447 cache_info->cache_filename);
5448 return(MagickFalse);
5450 if ((cache_info->columns == nexus_info->region.width) &&
5451 (extent <= MagickMaxBufferExtent))
5456 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5457 for (y=0; y < (ssize_t) rows; y++)
5459 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5460 cache_info->number_channels*sizeof(Quantum)+offset*
5461 cache_info->metacontent_extent,length,(const unsigned char *) p);
5462 if ((MagickSizeType) count != length)
5464 p+=nexus_info->region.width*cache_info->metacontent_extent;
5465 offset+=cache_info->columns;
5467 if (y < (ssize_t) rows)
5469 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5470 cache_info->cache_filename);
5471 return(MagickFalse);
5478 if ((cache_info->debug != MagickFalse) &&
5479 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5480 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5481 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5482 nexus_info->region.width,(double) nexus_info->region.height,(double)
5483 nexus_info->region.x,(double) nexus_info->region.y);
5488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5492 + W r i t e C a c h e P i x e l s %
5496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5498 % WritePixelCachePixels() writes image pixels to the specified region of the
5501 % The format of the WritePixelCachePixels() method is:
5503 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5504 % NexusInfo *nexus_info,ExceptionInfo *exception)
5506 % A description of each parameter follows:
5508 % o cache_info: the pixel cache.
5510 % o nexus_info: the cache nexus to write the pixels.
5512 % o exception: return any errors or warnings in this structure.
5515 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5516 NexusInfo *nexus_info,ExceptionInfo *exception)
5526 register const Quantum
5535 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5537 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5538 nexus_info->region.x;
5539 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5541 rows=nexus_info->region.height;
5543 p=nexus_info->pixels;
5544 switch (cache_info->type)
5553 Write pixels to memory.
5555 if ((cache_info->columns == nexus_info->region.width) &&
5556 (extent == (MagickSizeType) ((size_t) extent)))
5561 q=cache_info->pixels+offset*cache_info->number_channels;
5562 for (y=0; y < (ssize_t) rows; y++)
5564 (void) memcpy(q,p,(size_t) length);
5565 p+=nexus_info->region.width*cache_info->number_channels;
5566 q+=cache_info->columns*cache_info->number_channels;
5573 Write pixels to disk.
5575 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5577 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5578 cache_info->cache_filename);
5579 return(MagickFalse);
5581 if ((cache_info->columns == nexus_info->region.width) &&
5582 (extent <= MagickMaxBufferExtent))
5587 for (y=0; y < (ssize_t) rows; y++)
5589 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5590 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5592 if ((MagickSizeType) count != length)
5594 p+=nexus_info->region.width*cache_info->number_channels;
5595 offset+=cache_info->columns;
5597 if (y < (ssize_t) rows)
5599 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5600 cache_info->cache_filename);
5601 return(MagickFalse);
5608 if ((cache_info->debug != MagickFalse) &&
5609 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5610 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5611 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5612 nexus_info->region.width,(double) nexus_info->region.height,(double)
5613 nexus_info->region.x,(double) nexus_info->region.y);