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-2012 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)
1198 if (cache_info->type == PingCache)
1200 p=cache_info->channel_map;
1201 q=clone_info->channel_map;
1202 if ((cache_info->columns == clone_info->columns) &&
1203 (cache_info->rows == clone_info->rows) &&
1204 (cache_info->number_channels == clone_info->number_channels) &&
1205 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1206 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1207 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1208 if (memcmp(p,q,cache_info->number_channels*sizeof(*p)) != 0)
1210 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
1214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1218 + C l o n e P i x e l C a c h e M e t h o d s %
1222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1224 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1227 % The format of the ClonePixelCacheMethods() method is:
1229 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1231 % A description of each parameter follows:
1233 % o clone: Specifies a pointer to a Cache structure.
1235 % o cache: the pixel cache.
1238 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1244 assert(clone != (Cache) NULL);
1245 source_info=(CacheInfo *) clone;
1246 assert(source_info->signature == MagickSignature);
1247 if (source_info->debug != MagickFalse)
1248 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1249 source_info->filename);
1250 assert(cache != (Cache) NULL);
1251 cache_info=(CacheInfo *) cache;
1252 assert(cache_info->signature == MagickSignature);
1253 source_info->methods=cache_info->methods;
1257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1261 + D e s t r o y I m a g e P i x e l C a c h e %
1265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1267 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1269 % The format of the DestroyImagePixelCache() method is:
1271 % void DestroyImagePixelCache(Image *image)
1273 % A description of each parameter follows:
1275 % o image: the image.
1278 static void DestroyImagePixelCache(Image *image)
1280 assert(image != (Image *) NULL);
1281 assert(image->signature == MagickSignature);
1282 if (image->debug != MagickFalse)
1283 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1284 if (image->cache == (void *) NULL)
1286 image->cache=DestroyPixelCache(image->cache);
1290 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1294 + D e s t r o y I m a g e P i x e l s %
1298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1300 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1302 % The format of the DestroyImagePixels() method is:
1304 % void DestroyImagePixels(Image *image)
1306 % A description of each parameter follows:
1308 % o image: the image.
1311 MagickExport void DestroyImagePixels(Image *image)
1316 assert(image != (const Image *) NULL);
1317 assert(image->signature == MagickSignature);
1318 if (image->debug != MagickFalse)
1319 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1320 assert(image->cache != (Cache) NULL);
1321 cache_info=(CacheInfo *) image->cache;
1322 assert(cache_info->signature == MagickSignature);
1323 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1325 cache_info->methods.destroy_pixel_handler(image);
1328 image->cache=DestroyPixelCache(image->cache);
1332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1336 + D e s t r o y P i x e l C a c h e %
1340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1342 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1344 % The format of the DestroyPixelCache() method is:
1346 % Cache DestroyPixelCache(Cache cache)
1348 % A description of each parameter follows:
1350 % o cache: the pixel cache.
1354 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1356 switch (cache_info->type)
1360 if (cache_info->mapped == MagickFalse)
1361 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
1362 cache_info->pixels);
1364 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1365 (size_t) cache_info->length);
1366 RelinquishMagickResource(MemoryResource,cache_info->length);
1371 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1372 cache_info->length);
1373 RelinquishMagickResource(MapResource,cache_info->length);
1377 if (cache_info->file != -1)
1378 (void) ClosePixelCacheOnDisk(cache_info);
1379 RelinquishMagickResource(DiskResource,cache_info->length);
1385 cache_info->type=UndefinedCache;
1386 cache_info->mapped=MagickFalse;
1387 cache_info->metacontent=(void *) NULL;
1390 MagickPrivate Cache DestroyPixelCache(Cache cache)
1395 assert(cache != (Cache) NULL);
1396 cache_info=(CacheInfo *) cache;
1397 assert(cache_info->signature == MagickSignature);
1398 if (cache_info->debug != MagickFalse)
1399 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1400 cache_info->filename);
1401 LockSemaphoreInfo(cache_info->semaphore);
1402 cache_info->reference_count--;
1403 if (cache_info->reference_count != 0)
1405 UnlockSemaphoreInfo(cache_info->semaphore);
1406 return((Cache) NULL);
1408 UnlockSemaphoreInfo(cache_info->semaphore);
1409 if (cache_resources != (SplayTreeInfo *) NULL)
1410 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1411 if (cache_info->debug != MagickFalse)
1414 message[MaxTextExtent];
1416 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1417 cache_info->filename);
1418 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1420 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1421 (cache_info->type != DiskCache)))
1422 RelinquishPixelCachePixels(cache_info);
1425 RelinquishPixelCachePixels(cache_info);
1426 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1428 *cache_info->cache_filename='\0';
1429 if (cache_info->nexus_info != (NexusInfo **) NULL)
1430 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1431 cache_info->number_threads);
1432 if (cache_info->random_info != (RandomInfo *) NULL)
1433 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1434 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1435 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1436 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1437 DestroySemaphoreInfo(&cache_info->semaphore);
1438 cache_info->signature=(~MagickSignature);
1439 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1449 + D e s t r o y P i x e l C a c h e N e x u s %
1453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1455 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1457 % The format of the DestroyPixelCacheNexus() method is:
1459 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1460 % const size_t number_threads)
1462 % A description of each parameter follows:
1464 % o nexus_info: the nexus to destroy.
1466 % o number_threads: the number of nexus threads.
1470 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1472 if (nexus_info->mapped == MagickFalse)
1473 (void) RelinquishMagickMemory(nexus_info->cache);
1475 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1476 nexus_info->cache=(Quantum *) NULL;
1477 nexus_info->pixels=(Quantum *) NULL;
1478 nexus_info->metacontent=(void *) NULL;
1479 nexus_info->length=0;
1480 nexus_info->mapped=MagickFalse;
1483 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1484 const size_t number_threads)
1489 assert(nexus_info != (NexusInfo **) NULL);
1490 for (i=0; i < (ssize_t) number_threads; i++)
1492 if (nexus_info[i]->cache != (Quantum *) NULL)
1493 RelinquishCacheNexusPixels(nexus_info[i]);
1494 nexus_info[i]->signature=(~MagickSignature);
1495 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1497 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1506 % G e t A u t h e n t i c M e t a c o n t e n t %
1510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1513 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1514 % returned if the associated pixels are not available.
1516 % The format of the GetAuthenticMetacontent() method is:
1518 % void *GetAuthenticMetacontent(const Image *image)
1520 % A description of each parameter follows:
1522 % o image: the image.
1525 MagickExport void *GetAuthenticMetacontent(const Image *image)
1531 id = GetOpenMPThreadId();
1536 assert(image != (const Image *) NULL);
1537 assert(image->signature == MagickSignature);
1538 assert(image->cache != (Cache) NULL);
1539 cache_info=(CacheInfo *) image->cache;
1540 assert(cache_info->signature == MagickSignature);
1541 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1542 (GetAuthenticMetacontentFromHandler) NULL)
1544 metacontent=cache_info->methods.
1545 get_authentic_metacontent_from_handler(image);
1546 return(metacontent);
1548 assert(id < (int) cache_info->number_threads);
1549 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1550 cache_info->nexus_info[id]);
1551 return(metacontent);
1555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1559 + 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 %
1563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1565 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1566 % with the last call to QueueAuthenticPixelsCache() or
1567 % GetAuthenticPixelsCache().
1569 % The format of the GetAuthenticMetacontentFromCache() method is:
1571 % void *GetAuthenticMetacontentFromCache(const Image *image)
1573 % A description of each parameter follows:
1575 % o image: the image.
1578 static void *GetAuthenticMetacontentFromCache(const Image *image)
1584 id = GetOpenMPThreadId();
1589 assert(image != (const Image *) NULL);
1590 assert(image->signature == MagickSignature);
1591 assert(image->cache != (Cache) NULL);
1592 cache_info=(CacheInfo *) image->cache;
1593 assert(cache_info->signature == MagickSignature);
1594 assert(id < (int) cache_info->number_threads);
1595 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1596 cache_info->nexus_info[id]);
1597 return(metacontent);
1601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1605 + 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 %
1609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1611 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1612 % disk pixel cache as defined by the geometry parameters. A pointer to the
1613 % pixels is returned if the pixels are transferred, otherwise a NULL is
1616 % The format of the GetAuthenticPixelCacheNexus() method is:
1618 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1619 % const ssize_t y,const size_t columns,const size_t rows,
1620 % NexusInfo *nexus_info,ExceptionInfo *exception)
1622 % A description of each parameter follows:
1624 % o image: the image.
1626 % o x,y,columns,rows: These values define the perimeter of a region of
1629 % o nexus_info: the cache nexus to return.
1631 % o exception: return any errors or warnings in this structure.
1635 static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
1636 NexusInfo *nexus_info)
1644 if (cache_info->type == PingCache)
1646 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1647 nexus_info->region.x;
1648 status=nexus_info->pixels == (cache_info->pixels+offset*
1649 cache_info->number_channels) ? MagickTrue : MagickFalse;
1653 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1654 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1655 NexusInfo *nexus_info,ExceptionInfo *exception)
1664 Transfer pixels from the cache.
1666 assert(image != (Image *) NULL);
1667 assert(image->signature == MagickSignature);
1668 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
1669 if (q == (Quantum *) NULL)
1670 return((Quantum *) NULL);
1671 cache_info=(CacheInfo *) image->cache;
1672 assert(cache_info->signature == MagickSignature);
1673 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1675 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1676 return((Quantum *) NULL);
1677 if (cache_info->metacontent_extent != 0)
1678 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1679 return((Quantum *) NULL);
1684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1688 + 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 %
1692 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1694 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1695 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1697 % The format of the GetAuthenticPixelsFromCache() method is:
1699 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1701 % A description of each parameter follows:
1703 % o image: the image.
1706 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1712 id = GetOpenMPThreadId();
1714 assert(image != (const Image *) NULL);
1715 assert(image->signature == MagickSignature);
1716 assert(image->cache != (Cache) NULL);
1717 cache_info=(CacheInfo *) image->cache;
1718 assert(cache_info->signature == MagickSignature);
1719 assert(id < (int) cache_info->number_threads);
1720 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1728 % G e t A u t h e n t i c P i x e l Q u e u e %
1732 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1734 % GetAuthenticPixelQueue() returns the authentic pixels associated
1735 % corresponding with the last call to QueueAuthenticPixels() or
1736 % GetAuthenticPixels().
1738 % The format of the GetAuthenticPixelQueue() method is:
1740 % Quantum *GetAuthenticPixelQueue(const Image image)
1742 % A description of each parameter follows:
1744 % o image: the image.
1747 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1753 id = GetOpenMPThreadId();
1755 assert(image != (const Image *) NULL);
1756 assert(image->signature == MagickSignature);
1757 assert(image->cache != (Cache) NULL);
1758 cache_info=(CacheInfo *) image->cache;
1759 assert(cache_info->signature == MagickSignature);
1760 if (cache_info->methods.get_authentic_pixels_from_handler !=
1761 (GetAuthenticPixelsFromHandler) NULL)
1762 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1763 assert(id < (int) cache_info->number_threads);
1764 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1772 % G e t A u t h e n t i c P i x e l s %
1775 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1777 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1778 % region is successfully accessed, a pointer to a Quantum array
1779 % representing the region is returned, otherwise NULL is returned.
1781 % The returned pointer may point to a temporary working copy of the pixels
1782 % or it may point to the original pixels in memory. Performance is maximized
1783 % if the selected region is part of one row, or one or more full rows, since
1784 % then there is opportunity to access the pixels in-place (without a copy)
1785 % if the image is in memory, or in a memory-mapped file. The returned pointer
1786 % must *never* be deallocated by the user.
1788 % Pixels accessed via the returned pointer represent a simple array of type
1789 % Quantum. If the image has corresponding metacontent,call
1790 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1791 % meta-content corresponding to the region. Once the Quantum array has
1792 % been updated, the changes must be saved back to the underlying image using
1793 % SyncAuthenticPixels() or they may be lost.
1795 % The format of the GetAuthenticPixels() method is:
1797 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1798 % const ssize_t y,const size_t columns,const size_t rows,
1799 % ExceptionInfo *exception)
1801 % A description of each parameter follows:
1803 % o image: the image.
1805 % o x,y,columns,rows: These values define the perimeter of a region of
1808 % o exception: return any errors or warnings in this structure.
1811 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1812 const ssize_t y,const size_t columns,const size_t rows,
1813 ExceptionInfo *exception)
1819 id = GetOpenMPThreadId();
1824 assert(image != (Image *) NULL);
1825 assert(image->signature == MagickSignature);
1826 assert(image->cache != (Cache) NULL);
1827 cache_info=(CacheInfo *) image->cache;
1828 assert(cache_info->signature == MagickSignature);
1829 if (cache_info->methods.get_authentic_pixels_handler !=
1830 (GetAuthenticPixelsHandler) NULL)
1832 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1836 assert(id < (int) cache_info->number_threads);
1837 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1838 cache_info->nexus_info[id],exception);
1843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1847 + G e t A u t h e n t i c P i x e l s C a c h e %
1851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1853 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1854 % as defined by the geometry parameters. A pointer to the pixels is returned
1855 % if the pixels are transferred, otherwise a NULL is returned.
1857 % The format of the GetAuthenticPixelsCache() method is:
1859 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1860 % const ssize_t y,const size_t columns,const size_t rows,
1861 % ExceptionInfo *exception)
1863 % A description of each parameter follows:
1865 % o image: the image.
1867 % o x,y,columns,rows: These values define the perimeter of a region of
1870 % o exception: return any errors or warnings in this structure.
1873 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1874 const ssize_t y,const size_t columns,const size_t rows,
1875 ExceptionInfo *exception)
1881 id = GetOpenMPThreadId();
1886 assert(image != (const Image *) NULL);
1887 assert(image->signature == MagickSignature);
1888 assert(image->cache != (Cache) NULL);
1889 cache_info=(CacheInfo *) image->cache;
1890 if (cache_info == (Cache) NULL)
1891 return((Quantum *) NULL);
1892 assert(cache_info->signature == MagickSignature);
1893 assert(id < (int) cache_info->number_threads);
1894 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1895 cache_info->nexus_info[id],exception);
1900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1904 + G e t I m a g e E x t e n t %
1908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1910 % GetImageExtent() returns the extent of the pixels associated corresponding
1911 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1913 % The format of the GetImageExtent() method is:
1915 % MagickSizeType GetImageExtent(const Image *image)
1917 % A description of each parameter follows:
1919 % o image: the image.
1922 MagickExport MagickSizeType GetImageExtent(const Image *image)
1928 id = GetOpenMPThreadId();
1930 assert(image != (Image *) NULL);
1931 assert(image->signature == MagickSignature);
1932 if (image->debug != MagickFalse)
1933 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1934 assert(image->cache != (Cache) NULL);
1935 cache_info=(CacheInfo *) image->cache;
1936 assert(cache_info->signature == MagickSignature);
1937 assert(id < (int) cache_info->number_threads);
1938 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1946 + G e t I m a g e P i x e l C a c h e %
1950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1952 % GetImagePixelCache() ensures that there is only a single reference to the
1953 % pixel cache to be modified, updating the provided cache pointer to point to
1954 % a clone of the original pixel cache if necessary.
1956 % The format of the GetImagePixelCache method is:
1958 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1959 % ExceptionInfo *exception)
1961 % A description of each parameter follows:
1963 % o image: the image.
1965 % o clone: any value other than MagickFalse clones the cache pixels.
1967 % o exception: return any errors or warnings in this structure.
1971 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1977 Does the image match the pixel cache morphology?
1979 cache_info=(CacheInfo *) image->cache;
1980 if ((image->storage_class != cache_info->storage_class) ||
1981 (image->colorspace != cache_info->colorspace) ||
1982 (image->matte != cache_info->matte) ||
1983 (image->columns != cache_info->columns) ||
1984 (image->rows != cache_info->rows) ||
1985 (image->number_channels != cache_info->number_channels) ||
1986 (image->metacontent_extent != cache_info->metacontent_extent) ||
1987 (cache_info->nexus_info == (NexusInfo **) NULL) ||
1988 (cache_info->number_threads < GetOpenMPMaximumThreads()))
1989 return(MagickFalse);
1993 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1994 ExceptionInfo *exception)
2003 static MagickSizeType
2009 cache_timestamp = 0;
2012 LockSemaphoreInfo(image->semaphore);
2013 if (cpu_throttle == 0)
2019 Set CPU throttle in milleseconds.
2021 cpu_throttle=MagickResourceInfinity;
2022 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2023 if (limit == (char *) NULL)
2024 limit=GetPolicyValue("throttle");
2025 if (limit != (char *) NULL)
2027 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2028 limit=DestroyString(limit);
2031 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2032 MagickDelay(cpu_throttle);
2033 if (time_limit == 0)
2036 Set the exire time in seconds.
2038 time_limit=GetMagickResourceLimit(TimeResource);
2039 cache_timestamp=time((time_t *) NULL);
2041 if ((time_limit != MagickResourceInfinity) &&
2042 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
2043 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2044 assert(image->cache != (Cache) NULL);
2045 cache_info=(CacheInfo *) image->cache;
2046 destroy=MagickFalse;
2047 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2049 LockSemaphoreInfo(cache_info->semaphore);
2050 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2061 clone_image=(*image);
2062 clone_image.semaphore=AllocateSemaphoreInfo();
2063 clone_image.reference_count=1;
2064 clone_image.cache=ClonePixelCache(cache_info);
2065 clone_info=(CacheInfo *) clone_image.cache;
2066 status=OpenPixelCache(&clone_image,IOMode,exception);
2067 if (status != MagickFalse)
2069 if (clone != MagickFalse)
2070 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2071 if (status != MagickFalse)
2073 if (cache_info->mode == ReadMode)
2074 cache_info->nexus_info=(NexusInfo **) NULL;
2076 image->cache=clone_image.cache;
2079 DestroySemaphoreInfo(&clone_image.semaphore);
2081 UnlockSemaphoreInfo(cache_info->semaphore);
2083 if (destroy != MagickFalse)
2084 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2085 if (status != MagickFalse)
2088 Ensure the image matches the pixel cache morphology.
2090 image->taint=MagickTrue;
2091 image->type=UndefinedType;
2092 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2093 status=OpenPixelCache(image,IOMode,exception);
2095 UnlockSemaphoreInfo(image->semaphore);
2096 if (status == MagickFalse)
2097 return((Cache) NULL);
2098 return(image->cache);
2102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2106 % G e t O n e A u t h e n t i c P i x e l %
2110 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2112 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2113 % location. The image background color is returned if an error occurs.
2115 % The format of the GetOneAuthenticPixel() method is:
2117 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2118 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2120 % A description of each parameter follows:
2122 % o image: the image.
2124 % o x,y: These values define the location of the pixel to return.
2126 % o pixel: return a pixel at the specified (x,y) location.
2128 % o exception: return any errors or warnings in this structure.
2131 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2132 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2143 assert(image != (Image *) NULL);
2144 assert(image->signature == MagickSignature);
2145 assert(image->cache != (Cache) NULL);
2146 cache_info=(CacheInfo *) image->cache;
2147 assert(cache_info->signature == MagickSignature);
2148 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2149 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2150 (GetOneAuthenticPixelFromHandler) NULL)
2151 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2153 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2154 if (q == (Quantum *) NULL)
2156 pixel[RedPixelChannel]=image->background_color.red;
2157 pixel[GreenPixelChannel]=image->background_color.green;
2158 pixel[BluePixelChannel]=image->background_color.blue;
2159 pixel[BlackPixelChannel]=image->background_color.black;
2160 pixel[AlphaPixelChannel]=image->background_color.alpha;
2161 return(MagickFalse);
2163 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2168 channel=GetPixelChannelMapChannel(image,i);
2169 pixel[channel]=q[i];
2175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2179 + 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 %
2183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2185 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2186 % location. The image background color is returned if an error occurs.
2188 % The format of the GetOneAuthenticPixelFromCache() method is:
2190 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2191 % const ssize_t x,const ssize_t y,Quantum *pixel,
2192 % ExceptionInfo *exception)
2194 % A description of each parameter follows:
2196 % o image: the image.
2198 % o x,y: These values define the location of the pixel to return.
2200 % o pixel: return a pixel at the specified (x,y) location.
2202 % o exception: return any errors or warnings in this structure.
2205 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2206 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2212 id = GetOpenMPThreadId();
2220 assert(image != (const Image *) NULL);
2221 assert(image->signature == MagickSignature);
2222 assert(image->cache != (Cache) NULL);
2223 cache_info=(CacheInfo *) image->cache;
2224 assert(cache_info->signature == MagickSignature);
2225 assert(id < (int) cache_info->number_threads);
2226 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2227 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2229 if (q == (Quantum *) NULL)
2231 pixel[RedPixelChannel]=image->background_color.red;
2232 pixel[GreenPixelChannel]=image->background_color.green;
2233 pixel[BluePixelChannel]=image->background_color.blue;
2234 pixel[BlackPixelChannel]=image->background_color.black;
2235 pixel[AlphaPixelChannel]=image->background_color.alpha;
2236 return(MagickFalse);
2238 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2243 channel=GetPixelChannelMapChannel(image,i);
2244 pixel[channel]=q[i];
2250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2254 % G e t O n e V i r t u a l P i x e l %
2258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2260 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2261 % (x,y) location. The image background color is returned if an error occurs.
2262 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2264 % The format of the GetOneVirtualPixel() method is:
2266 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2267 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2269 % A description of each parameter follows:
2271 % o image: the image.
2273 % o x,y: These values define the location of the pixel to return.
2275 % o pixel: return a pixel at the specified (x,y) location.
2277 % o exception: return any errors or warnings in this structure.
2280 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2281 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2287 id = GetOpenMPThreadId();
2295 assert(image != (const Image *) NULL);
2296 assert(image->signature == MagickSignature);
2297 assert(image->cache != (Cache) NULL);
2298 cache_info=(CacheInfo *) image->cache;
2299 assert(cache_info->signature == MagickSignature);
2300 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2301 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2302 (GetOneVirtualPixelFromHandler) NULL)
2303 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2304 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2305 assert(id < (int) cache_info->number_threads);
2306 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2307 1UL,1UL,cache_info->nexus_info[id],exception);
2308 if (p == (const Quantum *) NULL)
2310 pixel[RedPixelChannel]=image->background_color.red;
2311 pixel[GreenPixelChannel]=image->background_color.green;
2312 pixel[BluePixelChannel]=image->background_color.blue;
2313 pixel[BlackPixelChannel]=image->background_color.black;
2314 pixel[AlphaPixelChannel]=image->background_color.alpha;
2315 return(MagickFalse);
2317 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2322 channel=GetPixelChannelMapChannel(image,i);
2323 pixel[channel]=p[i];
2329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2333 + 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 %
2337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2339 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2340 % specified (x,y) location. The image background color is returned if an
2343 % The format of the GetOneVirtualPixelFromCache() method is:
2345 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2346 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2347 % Quantum *pixel,ExceptionInfo *exception)
2349 % A description of each parameter follows:
2351 % o image: the image.
2353 % o virtual_pixel_method: the virtual pixel method.
2355 % o x,y: These values define the location of the pixel to return.
2357 % o pixel: return a pixel at the specified (x,y) location.
2359 % o exception: return any errors or warnings in this structure.
2362 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2363 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2364 Quantum *pixel,ExceptionInfo *exception)
2370 id = GetOpenMPThreadId();
2378 assert(image != (const Image *) NULL);
2379 assert(image->signature == MagickSignature);
2380 assert(image->cache != (Cache) NULL);
2381 cache_info=(CacheInfo *) image->cache;
2382 assert(cache_info->signature == MagickSignature);
2383 assert(id < (int) cache_info->number_threads);
2384 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2385 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2386 cache_info->nexus_info[id],exception);
2387 if (p == (const Quantum *) NULL)
2389 pixel[RedPixelChannel]=image->background_color.red;
2390 pixel[GreenPixelChannel]=image->background_color.green;
2391 pixel[BluePixelChannel]=image->background_color.blue;
2392 pixel[BlackPixelChannel]=image->background_color.black;
2393 pixel[AlphaPixelChannel]=image->background_color.alpha;
2394 return(MagickFalse);
2396 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2401 channel=GetPixelChannelMapChannel(image,i);
2402 pixel[channel]=p[i];
2408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2412 % G e t O n e V i r t u a l P i x e l I n f o %
2416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2418 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2419 % location. The image background color is returned if an error occurs. If
2420 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2422 % The format of the GetOneVirtualPixelInfo() method is:
2424 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2425 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2426 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2428 % A description of each parameter follows:
2430 % o image: the image.
2432 % o virtual_pixel_method: the virtual pixel method.
2434 % o x,y: these values define the location of the pixel to return.
2436 % o pixel: return a pixel at the specified (x,y) location.
2438 % o exception: return any errors or warnings in this structure.
2441 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2442 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2443 PixelInfo *pixel,ExceptionInfo *exception)
2449 id = GetOpenMPThreadId();
2451 register const Quantum
2454 assert(image != (const Image *) NULL);
2455 assert(image->signature == MagickSignature);
2456 assert(image->cache != (Cache) NULL);
2457 cache_info=(CacheInfo *) image->cache;
2458 assert(cache_info->signature == MagickSignature);
2459 assert(id < (int) cache_info->number_threads);
2460 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2461 cache_info->nexus_info[id],exception);
2462 GetPixelInfo(image,pixel);
2463 if (p == (const Quantum *) NULL)
2464 return(MagickFalse);
2465 GetPixelInfoPixel(image,p,pixel);
2470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2474 + G e t P i x e l C a c h e C o l o r s p a c e %
2478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2480 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2482 % The format of the GetPixelCacheColorspace() method is:
2484 % Colorspace GetPixelCacheColorspace(Cache cache)
2486 % A description of each parameter follows:
2488 % o cache: the pixel cache.
2491 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2496 assert(cache != (Cache) NULL);
2497 cache_info=(CacheInfo *) cache;
2498 assert(cache_info->signature == MagickSignature);
2499 if (cache_info->debug != MagickFalse)
2500 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2501 cache_info->filename);
2502 return(cache_info->colorspace);
2506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2510 + G e t P i x e l C a c h e M e t h o d s %
2514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2516 % GetPixelCacheMethods() initializes the CacheMethods structure.
2518 % The format of the GetPixelCacheMethods() method is:
2520 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2522 % A description of each parameter follows:
2524 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2527 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2529 assert(cache_methods != (CacheMethods *) NULL);
2530 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2531 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2532 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2533 cache_methods->get_virtual_metacontent_from_handler=
2534 GetVirtualMetacontentFromCache;
2535 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2536 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2537 cache_methods->get_authentic_metacontent_from_handler=
2538 GetAuthenticMetacontentFromCache;
2539 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2540 cache_methods->get_one_authentic_pixel_from_handler=
2541 GetOneAuthenticPixelFromCache;
2542 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2543 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2544 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2552 + G e t P i x e l C a c h e N e x u s E x t e n t %
2556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2558 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2559 % corresponding with the last call to SetPixelCacheNexusPixels() or
2560 % GetPixelCacheNexusPixels().
2562 % The format of the GetPixelCacheNexusExtent() method is:
2564 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2565 % NexusInfo *nexus_info)
2567 % A description of each parameter follows:
2569 % o nexus_info: the nexus info.
2572 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2573 NexusInfo *nexus_info)
2581 assert(cache != NULL);
2582 cache_info=(CacheInfo *) cache;
2583 assert(cache_info->signature == MagickSignature);
2584 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2586 return((MagickSizeType) cache_info->columns*cache_info->rows);
2591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2595 + 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 %
2599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2601 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2604 % The format of the GetPixelCacheNexusMetacontent() method is:
2606 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2607 % NexusInfo *nexus_info)
2609 % A description of each parameter follows:
2611 % o cache: the pixel cache.
2613 % o nexus_info: the cache nexus to return the meta-content.
2616 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2617 NexusInfo *nexus_info)
2622 assert(cache != NULL);
2623 cache_info=(CacheInfo *) cache;
2624 assert(cache_info->signature == MagickSignature);
2625 if (cache_info->storage_class == UndefinedClass)
2626 return((void *) NULL);
2627 return(nexus_info->metacontent);
2631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2635 + G e t P i x e l C a c h e N e x u s P i x e l s %
2639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2641 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2644 % The format of the GetPixelCacheNexusPixels() method is:
2646 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2647 % NexusInfo *nexus_info)
2649 % A description of each parameter follows:
2651 % o cache: the pixel cache.
2653 % o nexus_info: the cache nexus to return the pixels.
2656 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2657 NexusInfo *nexus_info)
2662 assert(cache != NULL);
2663 cache_info=(CacheInfo *) cache;
2664 assert(cache_info->signature == MagickSignature);
2665 if (cache_info->storage_class == UndefinedClass)
2666 return((Quantum *) NULL);
2667 return(nexus_info->pixels);
2671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2675 + G e t P i x e l C a c h e P i x e l s %
2679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2681 % GetPixelCachePixels() returns the pixels associated with the specified image.
2683 % The format of the GetPixelCachePixels() method is:
2685 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2686 % ExceptionInfo *exception)
2688 % A description of each parameter follows:
2690 % o image: the image.
2692 % o length: the pixel cache length.
2694 % o exception: return any errors or warnings in this structure.
2697 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2698 ExceptionInfo *exception)
2703 assert(image != (const Image *) NULL);
2704 assert(image->signature == MagickSignature);
2705 assert(image->cache != (Cache) NULL);
2706 assert(length != (MagickSizeType *) NULL);
2707 assert(exception != (ExceptionInfo *) NULL);
2708 assert(exception->signature == MagickSignature);
2709 cache_info=(CacheInfo *) image->cache;
2710 assert(cache_info->signature == MagickSignature);
2712 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2713 return((void *) NULL);
2714 *length=cache_info->length;
2715 return((void *) cache_info->pixels);
2719 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2723 + 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 %
2727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2729 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2731 % The format of the GetPixelCacheStorageClass() method is:
2733 % ClassType GetPixelCacheStorageClass(Cache cache)
2735 % A description of each parameter follows:
2737 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2739 % o cache: the pixel cache.
2742 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2747 assert(cache != (Cache) NULL);
2748 cache_info=(CacheInfo *) cache;
2749 assert(cache_info->signature == MagickSignature);
2750 if (cache_info->debug != MagickFalse)
2751 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2752 cache_info->filename);
2753 return(cache_info->storage_class);
2757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2761 + G e t P i x e l C a c h e T i l e S i z e %
2765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2767 % GetPixelCacheTileSize() returns the pixel cache tile size.
2769 % The format of the GetPixelCacheTileSize() method is:
2771 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2774 % A description of each parameter follows:
2776 % o image: the image.
2778 % o width: the optimize cache tile width in pixels.
2780 % o height: the optimize cache tile height in pixels.
2783 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2789 assert(image != (Image *) NULL);
2790 assert(image->signature == MagickSignature);
2791 if (image->debug != MagickFalse)
2792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2793 cache_info=(CacheInfo *) image->cache;
2794 assert(cache_info->signature == MagickSignature);
2795 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2796 if (GetPixelCacheType(image) == DiskCache)
2797 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2806 + G e t P i x e l C a c h e T y p e %
2810 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2812 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2814 % The format of the GetPixelCacheType() method is:
2816 % CacheType GetPixelCacheType(const Image *image)
2818 % A description of each parameter follows:
2820 % o image: the image.
2823 MagickPrivate CacheType GetPixelCacheType(const Image *image)
2828 assert(image != (Image *) NULL);
2829 assert(image->signature == MagickSignature);
2830 assert(image->cache != (Cache) NULL);
2831 cache_info=(CacheInfo *) image->cache;
2832 assert(cache_info->signature == MagickSignature);
2833 return(cache_info->type);
2837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2841 + 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 %
2845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2848 % pixel cache. A virtual pixel is any pixel access that is outside the
2849 % boundaries of the image cache.
2851 % The format of the GetPixelCacheVirtualMethod() method is:
2853 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2855 % A description of each parameter follows:
2857 % o image: the image.
2860 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2865 assert(image != (Image *) NULL);
2866 assert(image->signature == MagickSignature);
2867 assert(image->cache != (Cache) NULL);
2868 cache_info=(CacheInfo *) image->cache;
2869 assert(cache_info->signature == MagickSignature);
2870 return(cache_info->virtual_pixel_method);
2874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2878 + 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 %
2882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2884 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2885 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2887 % The format of the GetVirtualMetacontentFromCache() method is:
2889 % void *GetVirtualMetacontentFromCache(const Image *image)
2891 % A description of each parameter follows:
2893 % o image: the image.
2896 static const void *GetVirtualMetacontentFromCache(const Image *image)
2902 id = GetOpenMPThreadId();
2907 assert(image != (const Image *) NULL);
2908 assert(image->signature == MagickSignature);
2909 assert(image->cache != (Cache) NULL);
2910 cache_info=(CacheInfo *) image->cache;
2911 assert(cache_info->signature == MagickSignature);
2912 assert(id < (int) cache_info->number_threads);
2913 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2914 cache_info->nexus_info[id]);
2915 return(metacontent);
2919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2923 + 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 %
2927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2929 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2932 % The format of the GetVirtualMetacontentFromNexus() method is:
2934 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2935 % NexusInfo *nexus_info)
2937 % A description of each parameter follows:
2939 % o cache: the pixel cache.
2941 % o nexus_info: the cache nexus to return the meta-content.
2944 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2945 NexusInfo *nexus_info)
2950 assert(cache != (Cache) NULL);
2951 cache_info=(CacheInfo *) cache;
2952 assert(cache_info->signature == MagickSignature);
2953 if (cache_info->storage_class == UndefinedClass)
2954 return((void *) NULL);
2955 return(nexus_info->metacontent);
2959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2963 % G e t V i r t u a l M e t a c o n t e n t %
2967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2969 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2970 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2971 % returned if the meta-content are not available.
2973 % The format of the GetVirtualMetacontent() method is:
2975 % const void *GetVirtualMetacontent(const Image *image)
2977 % A description of each parameter follows:
2979 % o image: the image.
2982 MagickExport const void *GetVirtualMetacontent(const Image *image)
2988 id = GetOpenMPThreadId();
2993 assert(image != (const Image *) NULL);
2994 assert(image->signature == MagickSignature);
2995 assert(image->cache != (Cache) NULL);
2996 cache_info=(CacheInfo *) image->cache;
2997 assert(cache_info->signature == MagickSignature);
2998 if (cache_info->methods.get_virtual_metacontent_from_handler !=
2999 (GetVirtualMetacontentFromHandler) NULL)
3001 metacontent=cache_info->methods.
3002 get_virtual_metacontent_from_handler(image);
3003 return(metacontent);
3005 assert(id < (int) cache_info->number_threads);
3006 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3007 cache_info->nexus_info[id]);
3008 return(metacontent);
3012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3016 + 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 %
3020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3022 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3023 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3024 % is returned if the pixels are transferred, otherwise a NULL is returned.
3026 % The format of the GetVirtualPixelsFromNexus() method is:
3028 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
3029 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3030 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
3031 % ExceptionInfo *exception)
3033 % A description of each parameter follows:
3035 % o image: the image.
3037 % o virtual_pixel_method: the virtual pixel method.
3039 % o x,y,columns,rows: These values define the perimeter of a region of
3042 % o nexus_info: the cache nexus to acquire.
3044 % o exception: return any errors or warnings in this structure.
3051 0, 48, 12, 60, 3, 51, 15, 63,
3052 32, 16, 44, 28, 35, 19, 47, 31,
3053 8, 56, 4, 52, 11, 59, 7, 55,
3054 40, 24, 36, 20, 43, 27, 39, 23,
3055 2, 50, 14, 62, 1, 49, 13, 61,
3056 34, 18, 46, 30, 33, 17, 45, 29,
3057 10, 58, 6, 54, 9, 57, 5, 53,
3058 42, 26, 38, 22, 41, 25, 37, 21
3061 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3066 index=x+DitherMatrix[x & 0x07]-32L;
3069 if (index >= (ssize_t) columns)
3070 return((ssize_t) columns-1L);
3074 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3079 index=y+DitherMatrix[y & 0x07]-32L;
3082 if (index >= (ssize_t) rows)
3083 return((ssize_t) rows-1L);
3087 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3091 if (x >= (ssize_t) columns)
3092 return((ssize_t) (columns-1));
3096 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3100 if (y >= (ssize_t) rows)
3101 return((ssize_t) (rows-1));
3105 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3107 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3110 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3112 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3115 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3116 const size_t extent)
3122 Compute the remainder of dividing offset by extent. It returns not only
3123 the quotient (tile the offset falls in) but also the positive remainer
3124 within that tile such that 0 <= remainder < extent. This method is
3125 essentially a ldiv() using a floored modulo division rather than the
3126 normal default truncated modulo division.
3128 modulo.quotient=offset/(ssize_t) extent;
3131 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3135 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3136 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3137 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3138 ExceptionInfo *exception)
3155 virtual_pixel[CompositePixelChannel];
3160 register const Quantum
3173 register unsigned char
3180 *virtual_metacontent;
3185 assert(image != (const Image *) NULL);
3186 assert(image->signature == MagickSignature);
3187 assert(image->cache != (Cache) NULL);
3188 cache_info=(CacheInfo *) image->cache;
3189 assert(cache_info->signature == MagickSignature);
3190 if (cache_info->type == UndefinedCache)
3191 return((const Quantum *) NULL);
3194 region.width=columns;
3196 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3197 if (pixels == (Quantum *) NULL)
3198 return((const Quantum *) NULL);
3200 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3201 nexus_info->region.x;
3202 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3203 nexus_info->region.width-1L;
3204 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3205 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3206 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3207 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3213 Pixel request is inside cache extents.
3215 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3217 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3218 if (status == MagickFalse)
3219 return((const Quantum *) NULL);
3220 if (cache_info->metacontent_extent != 0)
3222 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3223 if (status == MagickFalse)
3224 return((const Quantum *) NULL);
3229 Pixel request is outside cache extents.
3231 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3232 virtual_nexus=AcquirePixelCacheNexus(1);
3233 if (virtual_nexus == (NexusInfo **) NULL)
3235 if (virtual_nexus != (NexusInfo **) NULL)
3236 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3237 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3238 "UnableToGetCacheNexus","`%s'",image->filename);
3239 return((const Quantum *) NULL);
3241 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3242 sizeof(*virtual_pixel));
3243 virtual_metacontent=(void *) NULL;
3244 switch (virtual_pixel_method)
3246 case BackgroundVirtualPixelMethod:
3247 case BlackVirtualPixelMethod:
3248 case GrayVirtualPixelMethod:
3249 case TransparentVirtualPixelMethod:
3250 case MaskVirtualPixelMethod:
3251 case WhiteVirtualPixelMethod:
3252 case EdgeVirtualPixelMethod:
3253 case CheckerTileVirtualPixelMethod:
3254 case HorizontalTileVirtualPixelMethod:
3255 case VerticalTileVirtualPixelMethod:
3257 if (cache_info->metacontent_extent != 0)
3260 Acquire a metacontent buffer.
3262 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3263 cache_info->metacontent_extent);
3264 if (virtual_metacontent == (void *) NULL)
3266 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3267 (void) ThrowMagickException(exception,GetMagickModule(),
3268 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3269 return((const Quantum *) NULL);
3271 (void) ResetMagickMemory(virtual_metacontent,0,
3272 cache_info->metacontent_extent);
3274 switch (virtual_pixel_method)
3276 case BlackVirtualPixelMethod:
3278 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3279 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3280 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3283 case GrayVirtualPixelMethod:
3285 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3286 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3288 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3291 case TransparentVirtualPixelMethod:
3293 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3294 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3295 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3298 case MaskVirtualPixelMethod:
3299 case WhiteVirtualPixelMethod:
3301 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3302 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3303 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3308 SetPixelRed(image,image->background_color.red,virtual_pixel);
3309 SetPixelGreen(image,image->background_color.green,virtual_pixel);
3310 SetPixelBlue(image,image->background_color.blue,virtual_pixel);
3311 if (image->colorspace == CMYKColorspace)
3312 SetPixelBlack(image,image->background_color.black,virtual_pixel);
3313 SetPixelAlpha(image,image->background_color.alpha,virtual_pixel);
3322 for (v=0; v < (ssize_t) rows; v++)
3324 for (u=0; u < (ssize_t) columns; u+=length)
3326 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3327 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3328 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3336 Transfer a single pixel.
3338 length=(MagickSizeType) 1;
3339 switch (virtual_pixel_method)
3343 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3344 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3345 1UL,1UL,*virtual_nexus,exception);
3346 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3349 case RandomVirtualPixelMethod:
3351 if (cache_info->random_info == (RandomInfo *) NULL)
3352 cache_info->random_info=AcquireRandomInfo();
3353 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3354 RandomX(cache_info->random_info,cache_info->columns),
3355 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3356 *virtual_nexus,exception);
3357 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3360 case DitherVirtualPixelMethod:
3362 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3363 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3364 1UL,1UL,*virtual_nexus,exception);
3365 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3368 case TileVirtualPixelMethod:
3370 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3371 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3372 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3373 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3375 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3378 case MirrorVirtualPixelMethod:
3380 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3381 if ((x_modulo.quotient & 0x01) == 1L)
3382 x_modulo.remainder=(ssize_t) cache_info->columns-
3383 x_modulo.remainder-1L;
3384 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3385 if ((y_modulo.quotient & 0x01) == 1L)
3386 y_modulo.remainder=(ssize_t) cache_info->rows-
3387 y_modulo.remainder-1L;
3388 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3389 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3391 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3394 case HorizontalTileEdgeVirtualPixelMethod:
3396 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3397 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3398 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3399 *virtual_nexus,exception);
3400 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3403 case VerticalTileEdgeVirtualPixelMethod:
3405 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3406 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3407 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3408 *virtual_nexus,exception);
3409 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3412 case BackgroundVirtualPixelMethod:
3413 case BlackVirtualPixelMethod:
3414 case GrayVirtualPixelMethod:
3415 case TransparentVirtualPixelMethod:
3416 case MaskVirtualPixelMethod:
3417 case WhiteVirtualPixelMethod:
3420 r=virtual_metacontent;
3423 case EdgeVirtualPixelMethod:
3424 case CheckerTileVirtualPixelMethod:
3426 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3427 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3428 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3431 r=virtual_metacontent;
3434 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3435 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3437 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3440 case HorizontalTileVirtualPixelMethod:
3442 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3445 r=virtual_metacontent;
3448 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3449 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3450 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3451 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3453 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3456 case VerticalTileVirtualPixelMethod:
3458 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3461 r=virtual_metacontent;
3464 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3465 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3466 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3467 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3469 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3473 if (p == (const Quantum *) NULL)
3475 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3477 q+=cache_info->number_channels;
3478 if ((s != (void *) NULL) && (r != (const void *) NULL))
3480 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3481 s+=cache_info->metacontent_extent;
3486 Transfer a run of pixels.
3488 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3489 length,1UL,*virtual_nexus,exception);
3490 if (p == (const Quantum *) NULL)
3492 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3493 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3494 q+=length*cache_info->number_channels;
3495 if ((r != (void *) NULL) && (s != (const void *) NULL))
3497 (void) memcpy(s,r,(size_t) length);
3498 s+=length*cache_info->metacontent_extent;
3505 if (virtual_metacontent != (void *) NULL)
3506 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3507 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3516 + G e t V i r t u a l P i x e l C a c h e %
3520 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3522 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3523 % cache as defined by the geometry parameters. A pointer to the pixels
3524 % is returned if the pixels are transferred, otherwise a NULL is returned.
3526 % The format of the GetVirtualPixelCache() method is:
3528 % const Quantum *GetVirtualPixelCache(const Image *image,
3529 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3530 % const ssize_t y,const size_t columns,const size_t rows,
3531 % ExceptionInfo *exception)
3533 % A description of each parameter follows:
3535 % o image: the image.
3537 % o virtual_pixel_method: the virtual pixel method.
3539 % o x,y,columns,rows: These values define the perimeter of a region of
3542 % o exception: return any errors or warnings in this structure.
3545 static const Quantum *GetVirtualPixelCache(const Image *image,
3546 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3547 const size_t columns,const size_t rows,ExceptionInfo *exception)
3553 id = GetOpenMPThreadId();
3558 assert(image != (const Image *) NULL);
3559 assert(image->signature == MagickSignature);
3560 assert(image->cache != (Cache) NULL);
3561 cache_info=(CacheInfo *) image->cache;
3562 assert(cache_info->signature == MagickSignature);
3563 assert(id < (int) cache_info->number_threads);
3564 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3565 cache_info->nexus_info[id],exception);
3570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3574 % G e t V i r t u a l P i x e l Q u e u e %
3578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3580 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3581 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3583 % The format of the GetVirtualPixelQueue() method is:
3585 % const Quantum *GetVirtualPixelQueue(const Image image)
3587 % A description of each parameter follows:
3589 % o image: the image.
3592 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3598 id = GetOpenMPThreadId();
3600 assert(image != (const Image *) NULL);
3601 assert(image->signature == MagickSignature);
3602 assert(image->cache != (Cache) NULL);
3603 cache_info=(CacheInfo *) image->cache;
3604 assert(cache_info->signature == MagickSignature);
3605 if (cache_info->methods.get_virtual_pixels_handler !=
3606 (GetVirtualPixelsHandler) NULL)
3607 return(cache_info->methods.get_virtual_pixels_handler(image));
3608 assert(id < (int) cache_info->number_threads);
3609 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3617 % G e t V i r t u a l P i x e l s %
3621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3623 % GetVirtualPixels() returns an immutable pixel region. If the
3624 % region is successfully accessed, a pointer to it is returned, otherwise
3625 % NULL is returned. The returned pointer may point to a temporary working
3626 % copy of the pixels or it may point to the original pixels in memory.
3627 % Performance is maximized if the selected region is part of one row, or one
3628 % or more full rows, since there is opportunity to access the pixels in-place
3629 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3630 % returned pointer must *never* be deallocated by the user.
3632 % Pixels accessed via the returned pointer represent a simple array of type
3633 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3634 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3635 % access the meta-content (of type void) corresponding to the the
3638 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3640 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3641 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3642 % GetCacheViewAuthenticPixels() instead.
3644 % The format of the GetVirtualPixels() method is:
3646 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3647 % const ssize_t y,const size_t columns,const size_t rows,
3648 % ExceptionInfo *exception)
3650 % A description of each parameter follows:
3652 % o image: the image.
3654 % o x,y,columns,rows: These values define the perimeter of a region of
3657 % o exception: return any errors or warnings in this structure.
3660 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3661 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3662 ExceptionInfo *exception)
3668 id = GetOpenMPThreadId();
3673 assert(image != (const Image *) NULL);
3674 assert(image->signature == MagickSignature);
3675 assert(image->cache != (Cache) NULL);
3676 cache_info=(CacheInfo *) image->cache;
3677 assert(cache_info->signature == MagickSignature);
3678 if (cache_info->methods.get_virtual_pixel_handler !=
3679 (GetVirtualPixelHandler) NULL)
3680 return(cache_info->methods.get_virtual_pixel_handler(image,
3681 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3682 assert(id < (int) cache_info->number_threads);
3683 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3684 columns,rows,cache_info->nexus_info[id],exception);
3689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3693 + 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 %
3697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3699 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3700 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3702 % The format of the GetVirtualPixelsCache() method is:
3704 % Quantum *GetVirtualPixelsCache(const Image *image)
3706 % A description of each parameter follows:
3708 % o image: the image.
3711 static const Quantum *GetVirtualPixelsCache(const Image *image)
3717 id = GetOpenMPThreadId();
3719 assert(image != (const Image *) NULL);
3720 assert(image->signature == MagickSignature);
3721 assert(image->cache != (Cache) NULL);
3722 cache_info=(CacheInfo *) image->cache;
3723 assert(cache_info->signature == MagickSignature);
3724 assert(id < (int) cache_info->number_threads);
3725 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3733 + G e t V i r t u a l P i x e l s N e x u s %
3737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3739 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3742 % The format of the GetVirtualPixelsNexus() method is:
3744 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3745 % NexusInfo *nexus_info)
3747 % A description of each parameter follows:
3749 % o cache: the pixel cache.
3751 % o nexus_info: the cache nexus to return the colormap pixels.
3754 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3755 NexusInfo *nexus_info)
3760 assert(cache != (Cache) NULL);
3761 cache_info=(CacheInfo *) cache;
3762 assert(cache_info->signature == MagickSignature);
3763 if (cache_info->storage_class == UndefinedClass)
3764 return((Quantum *) NULL);
3765 return((const Quantum *) nexus_info->pixels);
3769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3773 + M a s k P i x e l C a c h e N e x u s %
3777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3779 % MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3780 % The method returns MagickTrue if the pixel region is masked, otherwise
3783 % The format of the MaskPixelCacheNexus() method is:
3785 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3786 % NexusInfo *nexus_info,ExceptionInfo *exception)
3788 % A description of each parameter follows:
3790 % o image: the image.
3792 % o nexus_info: the cache nexus to clip.
3794 % o exception: return any errors or warnings in this structure.
3798 static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3799 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
3804 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
3809 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3810 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3811 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3812 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3813 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3814 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3815 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
3818 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3819 ExceptionInfo *exception)
3835 register const Quantum
3848 if (image->debug != MagickFalse)
3849 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3850 if (image->mask == (Image *) NULL)
3851 return(MagickFalse);
3852 cache_info=(CacheInfo *) image->cache;
3853 if (cache_info == (Cache) NULL)
3854 return(MagickFalse);
3855 image_nexus=AcquirePixelCacheNexus(1);
3856 clip_nexus=AcquirePixelCacheNexus(1);
3857 if ((image_nexus == (NexusInfo **) NULL) ||
3858 (clip_nexus == (NexusInfo **) NULL))
3859 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3860 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3861 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3862 nexus_info->region.height,image_nexus[0],exception);
3863 q=nexus_info->pixels;
3864 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3865 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3866 nexus_info->region.height,clip_nexus[0],exception);
3867 GetPixelInfo(image,&alpha);
3868 GetPixelInfo(image,&beta);
3869 number_pixels=(MagickSizeType) nexus_info->region.width*
3870 nexus_info->region.height;
3871 for (i=0; i < (ssize_t) number_pixels; i++)
3873 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
3875 GetPixelInfoPixel(image,p,&alpha);
3876 GetPixelInfoPixel(image,q,&beta);
3877 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
3878 &alpha,alpha.alpha,&beta);
3879 SetPixelRed(image,ClampToQuantum(beta.red),q);
3880 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3881 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3882 if (cache_info->colorspace == CMYKColorspace)
3883 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3884 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
3889 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3890 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3891 if (i < (ssize_t) number_pixels)
3892 return(MagickFalse);
3897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3901 + O p e n P i x e l C a c h e %
3905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3907 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3908 % dimensions, allocating space for the image pixels and optionally the
3909 % metacontent, and memory mapping the cache if it is disk based. The cache
3910 % nexus array is initialized as well.
3912 % The format of the OpenPixelCache() method is:
3914 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3915 % ExceptionInfo *exception)
3917 % A description of each parameter follows:
3919 % o image: the image.
3921 % o mode: ReadMode, WriteMode, or IOMode.
3923 % o exception: return any errors or warnings in this structure.
3927 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3929 cache_info->mapped=MagickFalse;
3930 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3931 cache_info->length);
3932 if (cache_info->pixels == (Quantum *) NULL)
3934 cache_info->mapped=MagickTrue;
3935 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3936 cache_info->length);
3940 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3950 cache_info=(CacheInfo *) image->cache;
3951 if (image->debug != MagickFalse)
3954 format[MaxTextExtent],
3955 message[MaxTextExtent];
3957 (void) FormatMagickSize(length,MagickFalse,format);
3958 (void) FormatLocaleString(message,MaxTextExtent,
3959 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3960 cache_info->cache_filename,cache_info->file,format);
3961 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3963 if (length != (MagickSizeType) ((MagickOffsetType) length))
3964 return(MagickFalse);
3965 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3967 return(MagickFalse);
3968 if ((MagickSizeType) extent >= length)
3970 offset=(MagickOffsetType) length-1;
3971 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3972 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3975 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3976 ExceptionInfo *exception)
3983 format[MaxTextExtent],
3984 message[MaxTextExtent];
3997 assert(image != (const Image *) NULL);
3998 assert(image->signature == MagickSignature);
3999 assert(image->cache != (Cache) NULL);
4000 if (image->debug != MagickFalse)
4001 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4002 if ((image->columns == 0) || (image->rows == 0))
4003 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4004 cache_info=(CacheInfo *) image->cache;
4005 assert(cache_info->signature == MagickSignature);
4006 source_info=(*cache_info);
4007 source_info.file=(-1);
4008 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4009 image->filename,(double) GetImageIndexInList(image));
4010 cache_info->storage_class=image->storage_class;
4011 cache_info->colorspace=image->colorspace;
4012 cache_info->matte=image->matte;
4013 cache_info->rows=image->rows;
4014 cache_info->columns=image->columns;
4015 InitializePixelChannelMap(image);
4016 cache_info->number_channels=GetPixelChannels(image);
4017 (void) memcpy(cache_info->channel_map,image->channel_map,
4018 cache_info->number_channels*sizeof(*image->channel_map));
4019 cache_info->metacontent_extent=image->metacontent_extent;
4020 cache_info->mode=mode;
4021 if (image->ping != MagickFalse)
4023 cache_info->type=PingCache;
4024 cache_info->pixels=(Quantum *) NULL;
4025 cache_info->metacontent=(void *) NULL;
4026 cache_info->length=0;
4029 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4030 packet_size=cache_info->number_channels*sizeof(Quantum);
4031 if (image->metacontent_extent != 0)
4032 packet_size+=cache_info->metacontent_extent;
4033 length=number_pixels*packet_size;
4034 columns=(size_t) (length/cache_info->rows/packet_size);
4035 if (cache_info->columns != columns)
4036 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4038 cache_info->length=length;
4039 if ((cache_info->type != UndefinedCache) &&
4040 (cache_info->columns <= source_info.columns) &&
4041 (cache_info->rows <= source_info.rows) &&
4042 (cache_info->number_channels <= source_info.number_channels) &&
4043 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4046 Inline pixel cache clone optimization.
4048 if ((cache_info->columns == source_info.columns) &&
4049 (cache_info->rows == source_info.rows) &&
4050 (cache_info->number_channels == source_info.number_channels) &&
4051 (cache_info->metacontent_extent == source_info.metacontent_extent))
4053 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4055 status=AcquireMagickResource(AreaResource,cache_info->length);
4056 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4057 cache_info->metacontent_extent);
4058 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4060 status=AcquireMagickResource(MemoryResource,cache_info->length);
4061 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4062 (cache_info->type == MemoryCache))
4064 AllocatePixelCachePixels(cache_info);
4065 if (cache_info->pixels == (Quantum *) NULL)
4066 cache_info->pixels=source_info.pixels;
4070 Create memory pixel cache.
4073 if (image->debug != MagickFalse)
4075 (void) FormatMagickSize(cache_info->length,MagickTrue,
4077 (void) FormatLocaleString(message,MaxTextExtent,
4078 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4079 cache_info->filename,cache_info->mapped != MagickFalse ?
4080 "anonymous" : "heap",(double) cache_info->columns,(double)
4081 cache_info->rows,(double) cache_info->number_channels,
4083 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4086 cache_info->type=MemoryCache;
4087 cache_info->metacontent=(void *) NULL;
4088 if (cache_info->metacontent_extent != 0)
4089 cache_info->metacontent=(void *) (cache_info->pixels+
4090 number_pixels*cache_info->number_channels);
4091 if (source_info.storage_class != UndefinedClass)
4093 status=ClonePixelCachePixels(cache_info,&source_info,
4095 RelinquishPixelCachePixels(&source_info);
4100 RelinquishMagickResource(MemoryResource,cache_info->length);
4103 Create pixel cache on disk.
4105 status=AcquireMagickResource(DiskResource,cache_info->length);
4106 if (status == MagickFalse)
4108 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4109 "CacheResourcesExhausted","`%s'",image->filename);
4110 return(MagickFalse);
4112 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4114 RelinquishMagickResource(DiskResource,cache_info->length);
4115 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4117 return(MagickFalse);
4119 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4120 cache_info->length);
4121 if (status == MagickFalse)
4123 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4125 return(MagickFalse);
4127 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4128 cache_info->metacontent_extent);
4129 if (length != (MagickSizeType) ((size_t) length))
4130 cache_info->type=DiskCache;
4133 status=AcquireMagickResource(MapResource,cache_info->length);
4134 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4135 (cache_info->type != MemoryCache))
4136 cache_info->type=DiskCache;
4139 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4140 cache_info->offset,(size_t) cache_info->length);
4141 if (cache_info->pixels == (Quantum *) NULL)
4143 cache_info->type=DiskCache;
4144 cache_info->pixels=source_info.pixels;
4149 Create file-backed memory-mapped pixel cache.
4152 (void) ClosePixelCacheOnDisk(cache_info);
4153 cache_info->type=MapCache;
4154 cache_info->mapped=MagickTrue;
4155 cache_info->metacontent=(void *) NULL;
4156 if (cache_info->metacontent_extent != 0)
4157 cache_info->metacontent=(void *) (cache_info->pixels+
4158 number_pixels*cache_info->number_channels);
4159 if (source_info.storage_class != UndefinedClass)
4161 status=ClonePixelCachePixels(cache_info,&source_info,
4163 RelinquishPixelCachePixels(&source_info);
4165 if (image->debug != MagickFalse)
4167 (void) FormatMagickSize(cache_info->length,MagickTrue,
4169 (void) FormatLocaleString(message,MaxTextExtent,
4170 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4171 cache_info->filename,cache_info->cache_filename,
4172 cache_info->file,(double) cache_info->columns,(double)
4173 cache_info->rows,(double) cache_info->number_channels,
4175 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4181 RelinquishMagickResource(MapResource,cache_info->length);
4184 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4186 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4187 RelinquishPixelCachePixels(&source_info);
4189 if (image->debug != MagickFalse)
4191 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4192 (void) FormatLocaleString(message,MaxTextExtent,
4193 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4194 cache_info->cache_filename,cache_info->file,(double)
4195 cache_info->columns,(double) cache_info->rows,(double)
4196 cache_info->number_channels,format);
4197 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4207 + P e r s i s t P i x e l C a c h e %
4211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4213 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4214 % persistent pixel cache is one that resides on disk and is not destroyed
4215 % when the program exits.
4217 % The format of the PersistPixelCache() method is:
4219 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4220 % const MagickBooleanType attach,MagickOffsetType *offset,
4221 % ExceptionInfo *exception)
4223 % A description of each parameter follows:
4225 % o image: the image.
4227 % o filename: the persistent pixel cache filename.
4229 % o attach: A value other than zero initializes the persistent pixel cache.
4231 % o initialize: A value other than zero initializes the persistent pixel
4234 % o offset: the offset in the persistent cache to store pixels.
4236 % o exception: return any errors or warnings in this structure.
4239 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4240 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4241 ExceptionInfo *exception)
4256 assert(image != (Image *) NULL);
4257 assert(image->signature == MagickSignature);
4258 if (image->debug != MagickFalse)
4259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4260 assert(image->cache != (void *) NULL);
4261 assert(filename != (const char *) NULL);
4262 assert(offset != (MagickOffsetType *) NULL);
4263 page_size=GetMagickPageSize();
4264 cache_info=(CacheInfo *) image->cache;
4265 assert(cache_info->signature == MagickSignature);
4266 if (attach != MagickFalse)
4269 Attach existing persistent pixel cache.
4271 if (image->debug != MagickFalse)
4272 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4273 "attach persistent cache");
4274 (void) CopyMagickString(cache_info->cache_filename,filename,
4276 cache_info->type=DiskCache;
4277 cache_info->offset=(*offset);
4278 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4279 return(MagickFalse);
4280 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4283 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4284 (cache_info->reference_count == 1))
4286 LockSemaphoreInfo(cache_info->semaphore);
4287 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4288 (cache_info->reference_count == 1))
4294 Usurp existing persistent pixel cache.
4296 status=rename_utf8(cache_info->cache_filename,filename);
4299 (void) CopyMagickString(cache_info->cache_filename,filename,
4301 *offset+=cache_info->length+page_size-(cache_info->length %
4303 UnlockSemaphoreInfo(cache_info->semaphore);
4304 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4305 if (image->debug != MagickFalse)
4306 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4307 "Usurp resident persistent cache");
4311 UnlockSemaphoreInfo(cache_info->semaphore);
4314 Clone persistent pixel cache.
4316 clone_image=(*image);
4317 clone_info=(CacheInfo *) clone_image.cache;
4318 image->cache=ClonePixelCache(cache_info);
4319 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4320 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4321 cache_info->type=DiskCache;
4322 cache_info->offset=(*offset);
4323 cache_info=(CacheInfo *) image->cache;
4324 status=OpenPixelCache(image,IOMode,exception);
4325 if (status != MagickFalse)
4326 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4327 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4328 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4337 + Q u e u e A u t h e n t i c N e x u s %
4341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4343 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4344 % by the region rectangle and returns a pointer to the region. This region is
4345 % subsequently transferred from the pixel cache with
4346 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4347 % pixels are transferred, otherwise a NULL is returned.
4349 % The format of the QueueAuthenticNexus() method is:
4351 % Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4352 % const ssize_t y,const size_t columns,const size_t rows,
4353 % const MagickBooleanType clone,NexusInfo *nexus_info,
4354 % ExceptionInfo *exception)
4356 % A description of each parameter follows:
4358 % o image: the image.
4360 % o x,y,columns,rows: These values define the perimeter of a region of
4363 % o nexus_info: the cache nexus to set.
4365 % o clone: clone the pixel cache.
4367 % o exception: return any errors or warnings in this structure.
4370 MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4371 const ssize_t y,const size_t columns,const size_t rows,
4372 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4387 Validate pixel cache geometry.
4389 assert(image != (const Image *) NULL);
4390 assert(image->signature == MagickSignature);
4391 assert(image->cache != (Cache) NULL);
4392 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4393 if (cache_info == (Cache) NULL)
4394 return((Quantum *) NULL);
4395 assert(cache_info->signature == MagickSignature);
4396 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4398 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4399 "NoPixelsDefinedInCache","`%s'",image->filename);
4400 return((Quantum *) NULL);
4402 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4403 (y >= (ssize_t) cache_info->rows))
4405 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4406 "PixelsAreNotAuthentic","`%s'",image->filename);
4407 return((Quantum *) NULL);
4409 offset=(MagickOffsetType) y*cache_info->columns+x;
4411 return((Quantum *) NULL);
4412 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4413 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4414 if ((MagickSizeType) offset >= number_pixels)
4415 return((Quantum *) NULL);
4421 region.width=columns;
4423 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4431 + 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 %
4435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4437 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4438 % defined by the region rectangle and returns a pointer to the region. This
4439 % region is subsequently transferred from the pixel cache with
4440 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4441 % pixels are transferred, otherwise a NULL is returned.
4443 % The format of the QueueAuthenticPixelsCache() method is:
4445 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4446 % const ssize_t y,const size_t columns,const size_t rows,
4447 % ExceptionInfo *exception)
4449 % A description of each parameter follows:
4451 % o image: the image.
4453 % o x,y,columns,rows: These values define the perimeter of a region of
4456 % o exception: return any errors or warnings in this structure.
4459 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4460 const ssize_t y,const size_t columns,const size_t rows,
4461 ExceptionInfo *exception)
4467 id = GetOpenMPThreadId();
4472 assert(image != (const Image *) NULL);
4473 assert(image->signature == MagickSignature);
4474 assert(image->cache != (Cache) NULL);
4475 cache_info=(CacheInfo *) image->cache;
4476 assert(cache_info->signature == MagickSignature);
4477 assert(id < (int) cache_info->number_threads);
4478 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4479 cache_info->nexus_info[id],exception);
4484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4488 % Q u e u e A u t h e n t i c P i x e l s %
4492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4494 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4495 % successfully initialized a pointer to a Quantum array representing the
4496 % region is returned, otherwise NULL is returned. The returned pointer may
4497 % point to a temporary working buffer for the pixels or it may point to the
4498 % final location of the pixels in memory.
4500 % Write-only access means that any existing pixel values corresponding to
4501 % the region are ignored. This is useful if the initial image is being
4502 % created from scratch, or if the existing pixel values are to be
4503 % completely replaced without need to refer to their pre-existing values.
4504 % The application is free to read and write the pixel buffer returned by
4505 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4506 % initialize the pixel array values. Initializing pixel array values is the
4507 % application's responsibility.
4509 % Performance is maximized if the selected region is part of one row, or
4510 % one or more full rows, since then there is opportunity to access the
4511 % pixels in-place (without a copy) if the image is in memory, or in a
4512 % memory-mapped file. The returned pointer must *never* be deallocated
4515 % Pixels accessed via the returned pointer represent a simple array of type
4516 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4517 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4518 % obtain the meta-content (of type void) corresponding to the region.
4519 % Once the Quantum (and/or Quantum) array has been updated, the
4520 % changes must be saved back to the underlying image using
4521 % SyncAuthenticPixels() or they may be lost.
4523 % The format of the QueueAuthenticPixels() method is:
4525 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4526 % const ssize_t y,const size_t columns,const size_t rows,
4527 % ExceptionInfo *exception)
4529 % A description of each parameter follows:
4531 % o image: the image.
4533 % o x,y,columns,rows: These values define the perimeter of a region of
4536 % o exception: return any errors or warnings in this structure.
4539 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4540 const ssize_t y,const size_t columns,const size_t rows,
4541 ExceptionInfo *exception)
4547 id = GetOpenMPThreadId();
4552 assert(image != (Image *) NULL);
4553 assert(image->signature == MagickSignature);
4554 assert(image->cache != (Cache) NULL);
4555 cache_info=(CacheInfo *) image->cache;
4556 assert(cache_info->signature == MagickSignature);
4557 if (cache_info->methods.queue_authentic_pixels_handler !=
4558 (QueueAuthenticPixelsHandler) NULL)
4560 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4561 columns,rows,exception);
4564 assert(id < (int) cache_info->number_threads);
4565 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4566 cache_info->nexus_info[id],exception);
4571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4575 + 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 %
4579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4581 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4584 % The format of the ReadPixelCacheMetacontent() method is:
4586 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4587 % NexusInfo *nexus_info,ExceptionInfo *exception)
4589 % A description of each parameter follows:
4591 % o cache_info: the pixel cache.
4593 % o nexus_info: the cache nexus to read the metacontent.
4595 % o exception: return any errors or warnings in this structure.
4598 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4599 NexusInfo *nexus_info,ExceptionInfo *exception)
4612 register unsigned char
4618 if (cache_info->metacontent_extent == 0)
4619 return(MagickFalse);
4620 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4622 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4623 nexus_info->region.x;
4624 length=(MagickSizeType) nexus_info->region.width*
4625 cache_info->metacontent_extent;
4626 rows=nexus_info->region.height;
4628 q=(unsigned char *) nexus_info->metacontent;
4629 switch (cache_info->type)
4634 register unsigned char
4638 Read meta-content from memory.
4640 if ((cache_info->columns == nexus_info->region.width) &&
4641 (extent == (MagickSizeType) ((size_t) extent)))
4646 p=(unsigned char *) cache_info->metacontent+offset*
4647 cache_info->metacontent_extent;
4648 for (y=0; y < (ssize_t) rows; y++)
4650 (void) memcpy(q,p,(size_t) length);
4651 p+=cache_info->metacontent_extent*cache_info->columns;
4652 q+=cache_info->metacontent_extent*nexus_info->region.width;
4659 Read meta content from disk.
4661 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4663 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4664 cache_info->cache_filename);
4665 return(MagickFalse);
4667 if ((cache_info->columns == nexus_info->region.width) &&
4668 (extent <= MagickMaxBufferExtent))
4673 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4674 for (y=0; y < (ssize_t) rows; y++)
4676 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4677 cache_info->number_channels*sizeof(Quantum)+offset*
4678 cache_info->metacontent_extent,length,(unsigned char *) q);
4679 if ((MagickSizeType) count != length)
4681 offset+=cache_info->columns;
4682 q+=cache_info->metacontent_extent*nexus_info->region.width;
4684 if (y < (ssize_t) rows)
4686 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4687 cache_info->cache_filename);
4688 return(MagickFalse);
4695 if ((cache_info->debug != MagickFalse) &&
4696 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4697 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4698 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4699 nexus_info->region.width,(double) nexus_info->region.height,(double)
4700 nexus_info->region.x,(double) nexus_info->region.y);
4705 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4709 + R e a d P i x e l C a c h e P i x e l s %
4713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4715 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4718 % The format of the ReadPixelCachePixels() method is:
4720 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4721 % NexusInfo *nexus_info,ExceptionInfo *exception)
4723 % A description of each parameter follows:
4725 % o cache_info: the pixel cache.
4727 % o nexus_info: the cache nexus to read the pixels.
4729 % o exception: return any errors or warnings in this structure.
4732 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4733 NexusInfo *nexus_info,ExceptionInfo *exception)
4752 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4754 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4755 nexus_info->region.x;
4756 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4758 rows=nexus_info->region.height;
4760 q=nexus_info->pixels;
4761 switch (cache_info->type)
4770 Read pixels from memory.
4772 if ((cache_info->columns == nexus_info->region.width) &&
4773 (extent == (MagickSizeType) ((size_t) extent)))
4778 p=cache_info->pixels+offset*cache_info->number_channels;
4779 for (y=0; y < (ssize_t) rows; y++)
4781 (void) memcpy(q,p,(size_t) length);
4782 p+=cache_info->number_channels*cache_info->columns;
4783 q+=cache_info->number_channels*nexus_info->region.width;
4790 Read pixels from disk.
4792 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4795 cache_info->cache_filename);
4796 return(MagickFalse);
4798 if ((cache_info->columns == nexus_info->region.width) &&
4799 (extent <= MagickMaxBufferExtent))
4804 for (y=0; y < (ssize_t) rows; y++)
4806 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4807 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4808 if ((MagickSizeType) count != length)
4810 offset+=cache_info->columns;
4811 q+=cache_info->number_channels*nexus_info->region.width;
4813 if (y < (ssize_t) rows)
4815 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4816 cache_info->cache_filename);
4817 return(MagickFalse);
4824 if ((cache_info->debug != MagickFalse) &&
4825 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4826 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4827 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4828 nexus_info->region.width,(double) nexus_info->region.height,(double)
4829 nexus_info->region.x,(double) nexus_info->region.y);
4834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4838 + R e f e r e n c e P i x e l C a c h e %
4842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4844 % ReferencePixelCache() increments the reference count associated with the
4845 % pixel cache returning a pointer to the cache.
4847 % The format of the ReferencePixelCache method is:
4849 % Cache ReferencePixelCache(Cache cache_info)
4851 % A description of each parameter follows:
4853 % o cache_info: the pixel cache.
4856 MagickPrivate Cache ReferencePixelCache(Cache cache)
4861 assert(cache != (Cache *) NULL);
4862 cache_info=(CacheInfo *) cache;
4863 assert(cache_info->signature == MagickSignature);
4864 LockSemaphoreInfo(cache_info->semaphore);
4865 cache_info->reference_count++;
4866 UnlockSemaphoreInfo(cache_info->semaphore);
4871 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4875 + S e t P i x e l C a c h e M e t h o d s %
4879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4881 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4883 % The format of the SetPixelCacheMethods() method is:
4885 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4887 % A description of each parameter follows:
4889 % o cache: the pixel cache.
4891 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4894 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4899 GetOneAuthenticPixelFromHandler
4900 get_one_authentic_pixel_from_handler;
4902 GetOneVirtualPixelFromHandler
4903 get_one_virtual_pixel_from_handler;
4906 Set cache pixel methods.
4908 assert(cache != (Cache) NULL);
4909 assert(cache_methods != (CacheMethods *) NULL);
4910 cache_info=(CacheInfo *) cache;
4911 assert(cache_info->signature == MagickSignature);
4912 if (cache_info->debug != MagickFalse)
4913 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4914 cache_info->filename);
4915 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4916 cache_info->methods.get_virtual_pixel_handler=
4917 cache_methods->get_virtual_pixel_handler;
4918 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4919 cache_info->methods.destroy_pixel_handler=
4920 cache_methods->destroy_pixel_handler;
4921 if (cache_methods->get_virtual_metacontent_from_handler !=
4922 (GetVirtualMetacontentFromHandler) NULL)
4923 cache_info->methods.get_virtual_metacontent_from_handler=
4924 cache_methods->get_virtual_metacontent_from_handler;
4925 if (cache_methods->get_authentic_pixels_handler !=
4926 (GetAuthenticPixelsHandler) NULL)
4927 cache_info->methods.get_authentic_pixels_handler=
4928 cache_methods->get_authentic_pixels_handler;
4929 if (cache_methods->queue_authentic_pixels_handler !=
4930 (QueueAuthenticPixelsHandler) NULL)
4931 cache_info->methods.queue_authentic_pixels_handler=
4932 cache_methods->queue_authentic_pixels_handler;
4933 if (cache_methods->sync_authentic_pixels_handler !=
4934 (SyncAuthenticPixelsHandler) NULL)
4935 cache_info->methods.sync_authentic_pixels_handler=
4936 cache_methods->sync_authentic_pixels_handler;
4937 if (cache_methods->get_authentic_pixels_from_handler !=
4938 (GetAuthenticPixelsFromHandler) NULL)
4939 cache_info->methods.get_authentic_pixels_from_handler=
4940 cache_methods->get_authentic_pixels_from_handler;
4941 if (cache_methods->get_authentic_metacontent_from_handler !=
4942 (GetAuthenticMetacontentFromHandler) NULL)
4943 cache_info->methods.get_authentic_metacontent_from_handler=
4944 cache_methods->get_authentic_metacontent_from_handler;
4945 get_one_virtual_pixel_from_handler=
4946 cache_info->methods.get_one_virtual_pixel_from_handler;
4947 if (get_one_virtual_pixel_from_handler !=
4948 (GetOneVirtualPixelFromHandler) NULL)
4949 cache_info->methods.get_one_virtual_pixel_from_handler=
4950 cache_methods->get_one_virtual_pixel_from_handler;
4951 get_one_authentic_pixel_from_handler=
4952 cache_methods->get_one_authentic_pixel_from_handler;
4953 if (get_one_authentic_pixel_from_handler !=
4954 (GetOneAuthenticPixelFromHandler) NULL)
4955 cache_info->methods.get_one_authentic_pixel_from_handler=
4956 cache_methods->get_one_authentic_pixel_from_handler;
4960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4964 + S e t P i x e l C a c h e N e x u s P i x e l s %
4968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4970 % SetPixelCacheNexusPixels() defines the region of the cache for the
4971 % specified cache nexus.
4973 % The format of the SetPixelCacheNexusPixels() method is:
4975 % Quantum SetPixelCacheNexusPixels(const Image *image,
4976 % const RectangleInfo *region,NexusInfo *nexus_info,
4977 % ExceptionInfo *exception)
4979 % A description of each parameter follows:
4981 % o image: the image.
4983 % o region: A pointer to the RectangleInfo structure that defines the
4984 % region of this particular cache nexus.
4986 % o nexus_info: the cache nexus to set.
4988 % o exception: return any errors or warnings in this structure.
4992 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4993 NexusInfo *nexus_info,ExceptionInfo *exception)
4995 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4996 return(MagickFalse);
4997 nexus_info->mapped=MagickFalse;
4998 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
4999 nexus_info->length);
5000 if (nexus_info->cache == (Quantum *) NULL)
5002 nexus_info->mapped=MagickTrue;
5003 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
5004 nexus_info->length);
5006 if (nexus_info->cache == (Quantum *) NULL)
5008 (void) ThrowMagickException(exception,GetMagickModule(),
5009 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5010 cache_info->filename);
5011 return(MagickFalse);
5016 static Quantum *SetPixelCacheNexusPixels(const Image *image,
5017 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5029 cache_info=(CacheInfo *) image->cache;
5030 assert(cache_info->signature == MagickSignature);
5031 if (cache_info->type == UndefinedCache)
5032 return((Quantum *) NULL);
5033 nexus_info->region=(*region);
5034 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5035 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5041 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5042 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5043 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5044 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5045 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5046 ((nexus_info->region.width == cache_info->columns) ||
5047 ((nexus_info->region.width % cache_info->columns) == 0)))))
5053 Pixels are accessed directly from memory.
5055 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5056 nexus_info->region.x;
5057 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5059 nexus_info->metacontent=(void *) NULL;
5060 if (cache_info->metacontent_extent != 0)
5061 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5062 offset*cache_info->metacontent_extent;
5063 return(nexus_info->pixels);
5067 Pixels are stored in a cache region until they are synced to the cache.
5069 number_pixels=(MagickSizeType) nexus_info->region.width*
5070 nexus_info->region.height;
5071 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
5072 if (cache_info->metacontent_extent != 0)
5073 length+=number_pixels*cache_info->metacontent_extent;
5074 if (nexus_info->cache == (Quantum *) NULL)
5076 nexus_info->length=length;
5077 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5078 if (status == MagickFalse)
5080 nexus_info->length=0;
5081 return((Quantum *) NULL);
5085 if (nexus_info->length != length)
5087 RelinquishCacheNexusPixels(nexus_info);
5088 nexus_info->length=length;
5089 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5090 if (status == MagickFalse)
5092 nexus_info->length=0;
5093 return((Quantum *) NULL);
5096 nexus_info->pixels=nexus_info->cache;
5097 nexus_info->metacontent=(void *) NULL;
5098 if (cache_info->metacontent_extent != 0)
5099 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
5100 cache_info->number_channels);
5101 return(nexus_info->pixels);
5105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5109 % 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 %
5113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5115 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5116 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5117 % access that is outside the boundaries of the image cache.
5119 % The format of the SetPixelCacheVirtualMethod() method is:
5121 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5122 % const VirtualPixelMethod virtual_pixel_method)
5124 % A description of each parameter follows:
5126 % o image: the image.
5128 % o virtual_pixel_method: choose the type of virtual pixel.
5131 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5132 const VirtualPixelMethod virtual_pixel_method)
5140 assert(image != (Image *) NULL);
5141 assert(image->signature == MagickSignature);
5142 if (image->debug != MagickFalse)
5143 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5144 assert(image->cache != (Cache) NULL);
5145 cache_info=(CacheInfo *) image->cache;
5146 assert(cache_info->signature == MagickSignature);
5147 method=cache_info->virtual_pixel_method;
5148 cache_info->virtual_pixel_method=virtual_pixel_method;
5153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5157 + 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 %
5161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5163 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5164 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5165 % is synced, otherwise MagickFalse.
5167 % The format of the SyncAuthenticPixelCacheNexus() method is:
5169 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5170 % NexusInfo *nexus_info,ExceptionInfo *exception)
5172 % A description of each parameter follows:
5174 % o image: the image.
5176 % o nexus_info: the cache nexus to sync.
5178 % o exception: return any errors or warnings in this structure.
5181 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5182 NexusInfo *nexus_info,ExceptionInfo *exception)
5191 Transfer pixels to the cache.
5193 assert(image != (Image *) NULL);
5194 assert(image->signature == MagickSignature);
5195 if (image->cache == (Cache) NULL)
5196 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5197 cache_info=(CacheInfo *) image->cache;
5198 assert(cache_info->signature == MagickSignature);
5199 if (cache_info->type == UndefinedCache)
5200 return(MagickFalse);
5201 if ((image->clip_mask != (Image *) NULL) &&
5202 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5203 return(MagickFalse);
5204 if ((image->mask != (Image *) NULL) &&
5205 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5206 return(MagickFalse);
5207 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5209 assert(cache_info->signature == MagickSignature);
5210 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5211 if ((cache_info->metacontent_extent != 0) &&
5212 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5213 return(MagickFalse);
5218 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5222 + S y n c A u t h e n t i c P i x e l C a c h e %
5226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5228 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5229 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5230 % otherwise MagickFalse.
5232 % The format of the SyncAuthenticPixelsCache() method is:
5234 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5235 % ExceptionInfo *exception)
5237 % A description of each parameter follows:
5239 % o image: the image.
5241 % o exception: return any errors or warnings in this structure.
5244 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5245 ExceptionInfo *exception)
5251 id = GetOpenMPThreadId();
5256 assert(image != (Image *) NULL);
5257 assert(image->signature == MagickSignature);
5258 assert(image->cache != (Cache) NULL);
5259 cache_info=(CacheInfo *) image->cache;
5260 assert(cache_info->signature == MagickSignature);
5261 assert(id < (int) cache_info->number_threads);
5262 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5272 % S y n c A u t h e n t i c P i x e l s %
5276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5278 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5279 % The method returns MagickTrue if the pixel region is flushed, otherwise
5282 % The format of the SyncAuthenticPixels() method is:
5284 % MagickBooleanType SyncAuthenticPixels(Image *image,
5285 % ExceptionInfo *exception)
5287 % A description of each parameter follows:
5289 % o image: the image.
5291 % o exception: return any errors or warnings in this structure.
5294 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5295 ExceptionInfo *exception)
5301 id = GetOpenMPThreadId();
5306 assert(image != (Image *) NULL);
5307 assert(image->signature == MagickSignature);
5308 assert(image->cache != (Cache) NULL);
5309 cache_info=(CacheInfo *) image->cache;
5310 assert(cache_info->signature == MagickSignature);
5311 if (cache_info->methods.sync_authentic_pixels_handler !=
5312 (SyncAuthenticPixelsHandler) NULL)
5314 status=cache_info->methods.sync_authentic_pixels_handler(image,
5318 assert(id < (int) cache_info->number_threads);
5319 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5329 + S y n c I m a g e P i x e l C a c h e %
5333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5335 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5336 % The method returns MagickTrue if the pixel region is flushed, otherwise
5339 % The format of the SyncImagePixelCache() method is:
5341 % MagickBooleanType SyncImagePixelCache(Image *image,
5342 % ExceptionInfo *exception)
5344 % A description of each parameter follows:
5346 % o image: the image.
5348 % o exception: return any errors or warnings in this structure.
5351 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5352 ExceptionInfo *exception)
5357 assert(image != (Image *) NULL);
5358 assert(exception != (ExceptionInfo *) NULL);
5359 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5360 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5368 + 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 %
5372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5374 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5375 % of the pixel cache.
5377 % The format of the WritePixelCacheMetacontent() method is:
5379 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5380 % NexusInfo *nexus_info,ExceptionInfo *exception)
5382 % A description of each parameter follows:
5384 % o cache_info: the pixel cache.
5386 % o nexus_info: the cache nexus to write the meta-content.
5388 % o exception: return any errors or warnings in this structure.
5391 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5392 NexusInfo *nexus_info,ExceptionInfo *exception)
5402 register const unsigned char
5411 if (cache_info->metacontent_extent == 0)
5412 return(MagickFalse);
5413 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5415 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5416 nexus_info->region.x;
5417 length=(MagickSizeType) nexus_info->region.width*
5418 cache_info->metacontent_extent;
5419 rows=nexus_info->region.height;
5420 extent=(MagickSizeType) length*rows;
5421 p=(unsigned char *) nexus_info->metacontent;
5422 switch (cache_info->type)
5427 register unsigned char
5431 Write associated pixels to memory.
5433 if ((cache_info->columns == nexus_info->region.width) &&
5434 (extent == (MagickSizeType) ((size_t) extent)))
5439 q=(unsigned char *) cache_info->metacontent+offset*
5440 cache_info->metacontent_extent;
5441 for (y=0; y < (ssize_t) rows; y++)
5443 (void) memcpy(q,p,(size_t) length);
5444 p+=nexus_info->region.width*cache_info->metacontent_extent;
5445 q+=cache_info->columns*cache_info->metacontent_extent;
5452 Write associated pixels to disk.
5454 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5456 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5457 cache_info->cache_filename);
5458 return(MagickFalse);
5460 if ((cache_info->columns == nexus_info->region.width) &&
5461 (extent <= MagickMaxBufferExtent))
5466 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5467 for (y=0; y < (ssize_t) rows; y++)
5469 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5470 cache_info->number_channels*sizeof(Quantum)+offset*
5471 cache_info->metacontent_extent,length,(const unsigned char *) p);
5472 if ((MagickSizeType) count != length)
5474 p+=nexus_info->region.width*cache_info->metacontent_extent;
5475 offset+=cache_info->columns;
5477 if (y < (ssize_t) rows)
5479 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5480 cache_info->cache_filename);
5481 return(MagickFalse);
5488 if ((cache_info->debug != MagickFalse) &&
5489 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5490 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5491 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5492 nexus_info->region.width,(double) nexus_info->region.height,(double)
5493 nexus_info->region.x,(double) nexus_info->region.y);
5498 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5502 + W r i t e C a c h e P i x e l s %
5506 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5508 % WritePixelCachePixels() writes image pixels to the specified region of the
5511 % The format of the WritePixelCachePixels() method is:
5513 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5514 % NexusInfo *nexus_info,ExceptionInfo *exception)
5516 % A description of each parameter follows:
5518 % o cache_info: the pixel cache.
5520 % o nexus_info: the cache nexus to write the pixels.
5522 % o exception: return any errors or warnings in this structure.
5525 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5526 NexusInfo *nexus_info,ExceptionInfo *exception)
5536 register const Quantum
5545 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5547 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5548 nexus_info->region.x;
5549 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5551 rows=nexus_info->region.height;
5553 p=nexus_info->pixels;
5554 switch (cache_info->type)
5563 Write pixels to memory.
5565 if ((cache_info->columns == nexus_info->region.width) &&
5566 (extent == (MagickSizeType) ((size_t) extent)))
5571 q=cache_info->pixels+offset*cache_info->number_channels;
5572 for (y=0; y < (ssize_t) rows; y++)
5574 (void) memcpy(q,p,(size_t) length);
5575 p+=nexus_info->region.width*cache_info->number_channels;
5576 q+=cache_info->columns*cache_info->number_channels;
5583 Write pixels to disk.
5585 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5587 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5588 cache_info->cache_filename);
5589 return(MagickFalse);
5591 if ((cache_info->columns == nexus_info->region.width) &&
5592 (extent <= MagickMaxBufferExtent))
5597 for (y=0; y < (ssize_t) rows; y++)
5599 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5600 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5602 if ((MagickSizeType) count != length)
5604 p+=nexus_info->region.width*cache_info->number_channels;
5605 offset+=cache_info->columns;
5607 if (y < (ssize_t) rows)
5609 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5610 cache_info->cache_filename);
5611 return(MagickFalse);
5618 if ((cache_info->debug != MagickFalse) &&
5619 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5620 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5621 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5622 nexus_info->region.width,(double) nexus_info->region.height,(double)
5623 nexus_info->region.x,(double) nexus_info->region.y);