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 if (cache_info->mode != mode)
632 (void) ClosePixelCacheOnDisk(cache_info);
633 LockSemaphoreInfo(cache_info->disk_semaphore);
634 if (cache_info->file != -1)
636 UnlockSemaphoreInfo(cache_info->disk_semaphore);
637 return(MagickTrue); /* cache already open */
639 LimitPixelCacheDescriptors();
640 if (*cache_info->cache_filename == '\0')
641 file=AcquireUniqueFileResource(cache_info->cache_filename);
647 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
652 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
653 O_BINARY | O_EXCL,S_MODE);
655 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
661 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
664 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
670 UnlockSemaphoreInfo(cache_info->disk_semaphore);
673 (void) AcquireMagickResource(FileResource,1);
674 cache_info->mode=mode;
675 cache_info->file=file;
676 cache_info->timestamp=time(0);
677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
681 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682 const MagickOffsetType offset,const MagickSizeType length,
683 unsigned char *restrict buffer)
685 register MagickOffsetType
691 cache_info->timestamp=time(0);
692 #if !defined(MAGICKCORE_HAVE_PREAD)
693 LockSemaphoreInfo(cache_info->disk_semaphore);
694 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
697 return((MagickOffsetType) -1);
701 for (i=0; i < (MagickOffsetType) length; i+=count)
703 #if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
719 #if !defined(MAGICKCORE_HAVE_PREAD)
720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
725 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
727 const unsigned char *restrict buffer)
729 register MagickOffsetType
735 cache_info->timestamp=time(0);
736 #if !defined(MAGICKCORE_HAVE_PWRITE)
737 LockSemaphoreInfo(cache_info->disk_semaphore);
738 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
741 return((MagickOffsetType) -1);
745 for (i=0; i < (MagickOffsetType) length; i+=count)
747 #if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
763 #if !defined(MAGICKCORE_HAVE_PWRITE)
764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
769 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
770 CacheInfo *cache_info,ExceptionInfo *exception)
775 register MagickOffsetType
785 Clone pixel cache (both caches on disk).
787 if (cache_info->debug != MagickFalse)
788 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
789 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
791 if (blob == (unsigned char *) NULL)
793 (void) ThrowMagickException(exception,GetMagickModule(),
794 ResourceLimitError,"MemoryAllocationFailed","`%s'",
795 cache_info->filename);
798 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
800 blob=(unsigned char *) RelinquishMagickMemory(blob);
801 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
802 cache_info->cache_filename);
805 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
807 (void) ClosePixelCacheOnDisk(cache_info);
808 blob=(unsigned char *) RelinquishMagickMemory(blob);
809 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
810 clone_info->cache_filename);
814 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
816 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
817 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
821 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
822 cache_info->cache_filename);
825 length=(size_t) count;
826 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
827 if ((MagickSizeType) count != length)
829 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
830 clone_info->cache_filename);
834 (void) ClosePixelCacheOnDisk(clone_info);
835 (void) ClosePixelCacheOnDisk(cache_info);
836 blob=(unsigned char *) RelinquishMagickMemory(blob);
837 if (i < (MagickOffsetType) cache_info->length)
842 static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
843 CacheInfo *cache_info,ExceptionInfo *exception)
848 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
851 Clone pixel cache (both caches in memory).
853 if (cache_info->debug != MagickFalse)
854 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
855 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
859 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
862 Clone pixel cache (one cache on disk, one in memory).
864 if (cache_info->debug != MagickFalse)
865 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
866 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
868 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
869 cache_info->cache_filename);
872 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
873 cache_info->length,(unsigned char *) clone_info->pixels);
874 (void) ClosePixelCacheOnDisk(cache_info);
875 if ((MagickSizeType) count != cache_info->length)
877 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
878 cache_info->cache_filename);
883 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
886 Clone pixel cache (one cache on disk, one in memory).
888 if (clone_info->debug != MagickFalse)
889 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
890 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
892 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
893 clone_info->cache_filename);
896 count=WritePixelCacheRegion(clone_info,clone_info->offset,
897 clone_info->length,(unsigned char *) cache_info->pixels);
898 (void) ClosePixelCacheOnDisk(clone_info);
899 if ((MagickSizeType) count != clone_info->length)
901 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
902 clone_info->cache_filename);
908 Clone pixel cache (both caches on disk).
910 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
913 static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
914 CacheInfo *cache_info,ExceptionInfo *exception)
940 Clone pixel cache (unoptimized).
942 if (cache_info->debug != MagickFalse)
944 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
945 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
947 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
948 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
950 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
951 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
953 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
955 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
956 clone_info->number_channels)*sizeof(Quantum),MagickMax(
957 cache_info->metacontent_extent,clone_info->metacontent_extent));
958 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
959 if (blob == (unsigned char *) NULL)
961 (void) ThrowMagickException(exception,GetMagickModule(),
962 ResourceLimitError,"MemoryAllocationFailed","`%s'",
963 cache_info->filename);
966 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
969 if (cache_info->type == DiskCache)
971 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
973 blob=(unsigned char *) RelinquishMagickMemory(blob);
974 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
975 cache_info->cache_filename);
978 cache_offset=cache_info->offset;
980 if (clone_info->type == DiskCache)
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.
998 for (y=0; y < (ssize_t) cache_info->rows; y++)
1000 for (x=0; x < (ssize_t) cache_info->columns; x++)
1006 Read a set of pixel channels.
1008 length=cache_info->number_channels*sizeof(Quantum);
1009 if (cache_info->type != DiskCache)
1010 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1014 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1015 if ((MagickSizeType) count != length)
1021 cache_offset+=length;
1022 if ((y < (ssize_t) clone_info->rows) &&
1023 (x < (ssize_t) clone_info->columns))
1024 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
1036 Write a set of pixel channels.
1038 channel=clone_info->channel_map[i].channel;
1039 traits=cache_info->channel_map[channel].traits;
1040 if (traits == UndefinedPixelTrait)
1042 if (clone_info->type != DiskCache)
1043 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1044 (unsigned char *) &sans,sizeof(Quantum));
1047 count=WritePixelCacheRegion(clone_info,clone_offset,
1048 sizeof(Quantum),(unsigned char *) &sans);
1049 if ((MagickSizeType) count != sizeof(Quantum))
1058 offset=cache_info->channel_map[channel].offset;
1059 if (clone_info->type != DiskCache)
1060 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1061 blob+offset*sizeof(Quantum),sizeof(Quantum));
1064 count=WritePixelCacheRegion(clone_info,clone_offset,
1065 sizeof(Quantum),blob+offset*sizeof(Quantum));
1066 if ((MagickSizeType) count != sizeof(Quantum))
1073 clone_offset+=sizeof(Quantum);
1076 length=clone_info->number_channels*sizeof(Quantum);
1077 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1078 for ( ; x < (ssize_t) clone_info->columns; x++)
1081 Set remaining columns as undefined.
1083 if (clone_info->type != DiskCache)
1084 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1088 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1089 if ((MagickSizeType) count != length)
1095 clone_offset+=length;
1098 length=clone_info->number_channels*sizeof(Quantum);
1099 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1100 for ( ; y < (ssize_t) clone_info->rows; y++)
1103 Set remaining rows as undefined.
1105 for (x=0; x < (ssize_t) clone_info->columns; x++)
1107 if (clone_info->type != DiskCache)
1108 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1112 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1113 if ((MagickSizeType) count != length)
1119 clone_offset+=length;
1122 if ((cache_info->metacontent_extent != 0) ||
1123 (clone_info->metacontent_extent != 0))
1128 for (y=0; y < (ssize_t) cache_info->rows; y++)
1130 for (x=0; x < (ssize_t) cache_info->columns; x++)
1133 Read a set of metacontent.
1135 length=cache_info->metacontent_extent;
1136 if (cache_info->type != DiskCache)
1137 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1138 cache_offset,length);
1141 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1142 if ((MagickSizeType) count != length)
1148 cache_offset+=length;
1149 if ((y < (ssize_t) clone_info->rows) &&
1150 (x < (ssize_t) clone_info->columns))
1153 Write a set of metacontent.
1155 length=clone_info->metacontent_extent;
1156 if (clone_info->type != DiskCache)
1157 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1161 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1163 if ((MagickSizeType) count != length)
1169 clone_offset+=length;
1172 length=clone_info->metacontent_extent;
1173 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1174 for ( ; x < (ssize_t) clone_info->columns; x++)
1177 Set remaining columns as undefined.
1179 if (clone_info->type != DiskCache)
1180 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1184 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1185 if ((MagickSizeType) count != length)
1191 clone_offset+=length;
1194 length=clone_info->metacontent_extent;
1195 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1196 for ( ; y < (ssize_t) clone_info->rows; y++)
1199 Set remaining rows as undefined.
1201 for (x=0; x < (ssize_t) clone_info->columns; x++)
1203 if (clone_info->type != DiskCache)
1204 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1208 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1209 if ((MagickSizeType) count != length)
1215 clone_offset+=length;
1219 if (clone_info->type == DiskCache)
1220 (void) ClosePixelCacheOnDisk(clone_info);
1221 if (cache_info->type == DiskCache)
1222 (void) ClosePixelCacheOnDisk(cache_info);
1223 blob=(unsigned char *) RelinquishMagickMemory(blob);
1227 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1228 CacheInfo *cache_info,ExceptionInfo *exception)
1234 if (cache_info->type == PingCache)
1236 p=cache_info->channel_map;
1237 q=clone_info->channel_map;
1238 if ((cache_info->columns == clone_info->columns) &&
1239 (cache_info->rows == clone_info->rows) &&
1240 (cache_info->number_channels == clone_info->number_channels) &&
1241 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1242 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1243 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1244 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
1248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252 + C l o n e P i x e l C a c h e M e t h o d s %
1256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1261 % The format of the ClonePixelCacheMethods() method is:
1263 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1265 % A description of each parameter follows:
1267 % o clone: Specifies a pointer to a Cache structure.
1269 % o cache: the pixel cache.
1272 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1278 assert(clone != (Cache) NULL);
1279 source_info=(CacheInfo *) clone;
1280 assert(source_info->signature == MagickSignature);
1281 if (source_info->debug != MagickFalse)
1282 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1283 source_info->filename);
1284 assert(cache != (Cache) NULL);
1285 cache_info=(CacheInfo *) cache;
1286 assert(cache_info->signature == MagickSignature);
1287 source_info->methods=cache_info->methods;
1291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1295 + D e s t r o y I m a g e P i x e l C a c h e %
1299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1301 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1303 % The format of the DestroyImagePixelCache() method is:
1305 % void DestroyImagePixelCache(Image *image)
1307 % A description of each parameter follows:
1309 % o image: the image.
1312 static void DestroyImagePixelCache(Image *image)
1314 assert(image != (Image *) NULL);
1315 assert(image->signature == MagickSignature);
1316 if (image->debug != MagickFalse)
1317 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1318 if (image->cache == (void *) NULL)
1320 image->cache=DestroyPixelCache(image->cache);
1324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1328 + D e s t r o y I m a g e P i x e l s %
1332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1334 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1336 % The format of the DestroyImagePixels() method is:
1338 % void DestroyImagePixels(Image *image)
1340 % A description of each parameter follows:
1342 % o image: the image.
1345 MagickExport void DestroyImagePixels(Image *image)
1350 assert(image != (const Image *) NULL);
1351 assert(image->signature == MagickSignature);
1352 if (image->debug != MagickFalse)
1353 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1354 assert(image->cache != (Cache) NULL);
1355 cache_info=(CacheInfo *) image->cache;
1356 assert(cache_info->signature == MagickSignature);
1357 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1359 cache_info->methods.destroy_pixel_handler(image);
1362 image->cache=DestroyPixelCache(image->cache);
1366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1370 + D e s t r o y P i x e l C a c h e %
1374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1376 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1378 % The format of the DestroyPixelCache() method is:
1380 % Cache DestroyPixelCache(Cache cache)
1382 % A description of each parameter follows:
1384 % o cache: the pixel cache.
1388 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1390 switch (cache_info->type)
1394 if (cache_info->mapped == MagickFalse)
1395 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
1396 cache_info->pixels);
1398 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1399 (size_t) cache_info->length);
1400 RelinquishMagickResource(MemoryResource,cache_info->length);
1405 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1406 cache_info->length);
1407 RelinquishMagickResource(MapResource,cache_info->length);
1411 if (cache_info->file != -1)
1412 (void) ClosePixelCacheOnDisk(cache_info);
1413 RelinquishMagickResource(DiskResource,cache_info->length);
1419 cache_info->type=UndefinedCache;
1420 cache_info->mapped=MagickFalse;
1421 cache_info->metacontent=(void *) NULL;
1424 MagickPrivate Cache DestroyPixelCache(Cache cache)
1429 assert(cache != (Cache) NULL);
1430 cache_info=(CacheInfo *) cache;
1431 assert(cache_info->signature == MagickSignature);
1432 if (cache_info->debug != MagickFalse)
1433 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1434 cache_info->filename);
1435 LockSemaphoreInfo(cache_info->semaphore);
1436 cache_info->reference_count--;
1437 if (cache_info->reference_count != 0)
1439 UnlockSemaphoreInfo(cache_info->semaphore);
1440 return((Cache) NULL);
1442 UnlockSemaphoreInfo(cache_info->semaphore);
1443 if (cache_resources != (SplayTreeInfo *) NULL)
1444 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1445 if (cache_info->debug != MagickFalse)
1448 message[MaxTextExtent];
1450 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1451 cache_info->filename);
1452 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1454 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1455 (cache_info->type != DiskCache)))
1456 RelinquishPixelCachePixels(cache_info);
1459 RelinquishPixelCachePixels(cache_info);
1460 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1462 *cache_info->cache_filename='\0';
1463 if (cache_info->nexus_info != (NexusInfo **) NULL)
1464 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1465 cache_info->number_threads);
1466 if (cache_info->random_info != (RandomInfo *) NULL)
1467 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1468 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1469 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1470 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1471 DestroySemaphoreInfo(&cache_info->semaphore);
1472 cache_info->signature=(~MagickSignature);
1473 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1483 + D e s t r o y P i x e l C a c h e N e x u s %
1487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1489 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1491 % The format of the DestroyPixelCacheNexus() method is:
1493 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1494 % const size_t number_threads)
1496 % A description of each parameter follows:
1498 % o nexus_info: the nexus to destroy.
1500 % o number_threads: the number of nexus threads.
1504 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1506 if (nexus_info->mapped == MagickFalse)
1507 (void) RelinquishMagickMemory(nexus_info->cache);
1509 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1510 nexus_info->cache=(Quantum *) NULL;
1511 nexus_info->pixels=(Quantum *) NULL;
1512 nexus_info->metacontent=(void *) NULL;
1513 nexus_info->length=0;
1514 nexus_info->mapped=MagickFalse;
1517 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1518 const size_t number_threads)
1523 assert(nexus_info != (NexusInfo **) NULL);
1524 for (i=0; i < (ssize_t) number_threads; i++)
1526 if (nexus_info[i]->cache != (Quantum *) NULL)
1527 RelinquishCacheNexusPixels(nexus_info[i]);
1528 nexus_info[i]->signature=(~MagickSignature);
1529 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1531 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1540 % G e t A u t h e n t i c M e t a c o n t e n t %
1544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1547 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1548 % returned if the associated pixels are not available.
1550 % The format of the GetAuthenticMetacontent() method is:
1552 % void *GetAuthenticMetacontent(const Image *image)
1554 % A description of each parameter follows:
1556 % o image: the image.
1559 MagickExport void *GetAuthenticMetacontent(const Image *image)
1565 id = GetOpenMPThreadId();
1570 assert(image != (const Image *) NULL);
1571 assert(image->signature == MagickSignature);
1572 assert(image->cache != (Cache) NULL);
1573 cache_info=(CacheInfo *) image->cache;
1574 assert(cache_info->signature == MagickSignature);
1575 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1576 (GetAuthenticMetacontentFromHandler) NULL)
1578 metacontent=cache_info->methods.
1579 get_authentic_metacontent_from_handler(image);
1580 return(metacontent);
1582 assert(id < (int) cache_info->number_threads);
1583 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1584 cache_info->nexus_info[id]);
1585 return(metacontent);
1589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593 + 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 %
1597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1599 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1600 % with the last call to QueueAuthenticPixelsCache() or
1601 % GetAuthenticPixelsCache().
1603 % The format of the GetAuthenticMetacontentFromCache() method is:
1605 % void *GetAuthenticMetacontentFromCache(const Image *image)
1607 % A description of each parameter follows:
1609 % o image: the image.
1612 static void *GetAuthenticMetacontentFromCache(const Image *image)
1618 id = GetOpenMPThreadId();
1623 assert(image != (const Image *) NULL);
1624 assert(image->signature == MagickSignature);
1625 assert(image->cache != (Cache) NULL);
1626 cache_info=(CacheInfo *) image->cache;
1627 assert(cache_info->signature == MagickSignature);
1628 assert(id < (int) cache_info->number_threads);
1629 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1630 cache_info->nexus_info[id]);
1631 return(metacontent);
1635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639 + 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 %
1643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1645 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1646 % disk pixel cache as defined by the geometry parameters. A pointer to the
1647 % pixels is returned if the pixels are transferred, otherwise a NULL is
1650 % The format of the GetAuthenticPixelCacheNexus() method is:
1652 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1653 % const ssize_t y,const size_t columns,const size_t rows,
1654 % NexusInfo *nexus_info,ExceptionInfo *exception)
1656 % A description of each parameter follows:
1658 % o image: the image.
1660 % o x,y,columns,rows: These values define the perimeter of a region of
1663 % o nexus_info: the cache nexus to return.
1665 % o exception: return any errors or warnings in this structure.
1669 static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
1670 NexusInfo *nexus_info)
1678 if (cache_info->type == PingCache)
1680 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1681 nexus_info->region.x;
1682 status=nexus_info->pixels == (cache_info->pixels+offset*
1683 cache_info->number_channels) ? MagickTrue : MagickFalse;
1687 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1688 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1689 NexusInfo *nexus_info,ExceptionInfo *exception)
1698 Transfer pixels from the cache.
1700 assert(image != (Image *) NULL);
1701 assert(image->signature == MagickSignature);
1702 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
1703 if (q == (Quantum *) NULL)
1704 return((Quantum *) NULL);
1705 cache_info=(CacheInfo *) image->cache;
1706 assert(cache_info->signature == MagickSignature);
1707 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1709 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1710 return((Quantum *) NULL);
1711 if (cache_info->metacontent_extent != 0)
1712 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1713 return((Quantum *) NULL);
1718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1722 + 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 %
1726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1728 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1729 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1731 % The format of the GetAuthenticPixelsFromCache() method is:
1733 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1735 % A description of each parameter follows:
1737 % o image: the image.
1740 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1746 id = GetOpenMPThreadId();
1748 assert(image != (const Image *) NULL);
1749 assert(image->signature == MagickSignature);
1750 assert(image->cache != (Cache) NULL);
1751 cache_info=(CacheInfo *) image->cache;
1752 assert(cache_info->signature == MagickSignature);
1753 assert(id < (int) cache_info->number_threads);
1754 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1762 % G e t A u t h e n t i c P i x e l Q u e u e %
1766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1768 % GetAuthenticPixelQueue() returns the authentic pixels associated
1769 % corresponding with the last call to QueueAuthenticPixels() or
1770 % GetAuthenticPixels().
1772 % The format of the GetAuthenticPixelQueue() method is:
1774 % Quantum *GetAuthenticPixelQueue(const Image image)
1776 % A description of each parameter follows:
1778 % o image: the image.
1781 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1787 id = GetOpenMPThreadId();
1789 assert(image != (const Image *) NULL);
1790 assert(image->signature == MagickSignature);
1791 assert(image->cache != (Cache) NULL);
1792 cache_info=(CacheInfo *) image->cache;
1793 assert(cache_info->signature == MagickSignature);
1794 if (cache_info->methods.get_authentic_pixels_from_handler !=
1795 (GetAuthenticPixelsFromHandler) NULL)
1796 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1797 assert(id < (int) cache_info->number_threads);
1798 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1802 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1806 % G e t A u t h e n t i c P i x e l s %
1809 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1811 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1812 % region is successfully accessed, a pointer to a Quantum array
1813 % representing the region is returned, otherwise NULL is returned.
1815 % The returned pointer may point to a temporary working copy of the pixels
1816 % or it may point to the original pixels in memory. Performance is maximized
1817 % if the selected region is part of one row, or one or more full rows, since
1818 % then there is opportunity to access the pixels in-place (without a copy)
1819 % if the image is in memory, or in a memory-mapped file. The returned pointer
1820 % must *never* be deallocated by the user.
1822 % Pixels accessed via the returned pointer represent a simple array of type
1823 % Quantum. If the image has corresponding metacontent,call
1824 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1825 % meta-content corresponding to the region. Once the Quantum array has
1826 % been updated, the changes must be saved back to the underlying image using
1827 % SyncAuthenticPixels() or they may be lost.
1829 % The format of the GetAuthenticPixels() method is:
1831 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1832 % const ssize_t y,const size_t columns,const size_t rows,
1833 % ExceptionInfo *exception)
1835 % A description of each parameter follows:
1837 % o image: the image.
1839 % o x,y,columns,rows: These values define the perimeter of a region of
1842 % o exception: return any errors or warnings in this structure.
1845 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1846 const ssize_t y,const size_t columns,const size_t rows,
1847 ExceptionInfo *exception)
1853 id = GetOpenMPThreadId();
1858 assert(image != (Image *) NULL);
1859 assert(image->signature == MagickSignature);
1860 assert(image->cache != (Cache) NULL);
1861 cache_info=(CacheInfo *) image->cache;
1862 assert(cache_info->signature == MagickSignature);
1863 if (cache_info->methods.get_authentic_pixels_handler !=
1864 (GetAuthenticPixelsHandler) NULL)
1866 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1870 assert(id < (int) cache_info->number_threads);
1871 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1872 cache_info->nexus_info[id],exception);
1877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1881 + G e t A u t h e n t i c P i x e l s C a c h e %
1885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1887 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1888 % as defined by the geometry parameters. A pointer to the pixels is returned
1889 % if the pixels are transferred, otherwise a NULL is returned.
1891 % The format of the GetAuthenticPixelsCache() method is:
1893 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1894 % const ssize_t y,const size_t columns,const size_t rows,
1895 % ExceptionInfo *exception)
1897 % A description of each parameter follows:
1899 % o image: the image.
1901 % o x,y,columns,rows: These values define the perimeter of a region of
1904 % o exception: return any errors or warnings in this structure.
1907 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1908 const ssize_t y,const size_t columns,const size_t rows,
1909 ExceptionInfo *exception)
1915 id = GetOpenMPThreadId();
1920 assert(image != (const Image *) NULL);
1921 assert(image->signature == MagickSignature);
1922 assert(image->cache != (Cache) NULL);
1923 cache_info=(CacheInfo *) image->cache;
1924 if (cache_info == (Cache) NULL)
1925 return((Quantum *) NULL);
1926 assert(cache_info->signature == MagickSignature);
1927 assert(id < (int) cache_info->number_threads);
1928 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1929 cache_info->nexus_info[id],exception);
1934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1938 + G e t I m a g e E x t e n t %
1942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1944 % GetImageExtent() returns the extent of the pixels associated corresponding
1945 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1947 % The format of the GetImageExtent() method is:
1949 % MagickSizeType GetImageExtent(const Image *image)
1951 % A description of each parameter follows:
1953 % o image: the image.
1956 MagickExport MagickSizeType GetImageExtent(const Image *image)
1962 id = GetOpenMPThreadId();
1964 assert(image != (Image *) NULL);
1965 assert(image->signature == MagickSignature);
1966 if (image->debug != MagickFalse)
1967 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1968 assert(image->cache != (Cache) NULL);
1969 cache_info=(CacheInfo *) image->cache;
1970 assert(cache_info->signature == MagickSignature);
1971 assert(id < (int) cache_info->number_threads);
1972 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1976 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980 + G e t I m a g e P i x e l C a c h e %
1984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1986 % GetImagePixelCache() ensures that there is only a single reference to the
1987 % pixel cache to be modified, updating the provided cache pointer to point to
1988 % a clone of the original pixel cache if necessary.
1990 % The format of the GetImagePixelCache method is:
1992 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1993 % ExceptionInfo *exception)
1995 % A description of each parameter follows:
1997 % o image: the image.
1999 % o clone: any value other than MagickFalse clones the cache pixels.
2001 % o exception: return any errors or warnings in this structure.
2005 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2015 Does the image match the pixel cache morphology?
2017 cache_info=(CacheInfo *) image->cache;
2018 p=image->channel_map;
2019 q=cache_info->channel_map;
2020 if ((image->storage_class != cache_info->storage_class) ||
2021 (image->colorspace != cache_info->colorspace) ||
2022 (image->matte != cache_info->matte) ||
2023 (image->columns != cache_info->columns) ||
2024 (image->rows != cache_info->rows) ||
2025 (image->number_channels != cache_info->number_channels) ||
2026 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
2027 (image->metacontent_extent != cache_info->metacontent_extent) ||
2028 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2029 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2030 return(MagickFalse);
2034 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2035 ExceptionInfo *exception)
2044 static MagickSizeType
2050 cache_timestamp = 0;
2053 LockSemaphoreInfo(image->semaphore);
2054 if (cpu_throttle == 0)
2060 Set CPU throttle in milleseconds.
2062 cpu_throttle=MagickResourceInfinity;
2063 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2064 if (limit == (char *) NULL)
2065 limit=GetPolicyValue("throttle");
2066 if (limit != (char *) NULL)
2068 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2069 limit=DestroyString(limit);
2072 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2073 MagickDelay(cpu_throttle);
2074 if (time_limit == 0)
2077 Set the exire time in seconds.
2079 time_limit=GetMagickResourceLimit(TimeResource);
2080 cache_timestamp=time((time_t *) NULL);
2082 if ((time_limit != MagickResourceInfinity) &&
2083 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
2084 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2085 assert(image->cache != (Cache) NULL);
2086 cache_info=(CacheInfo *) image->cache;
2087 destroy=MagickFalse;
2088 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2090 LockSemaphoreInfo(cache_info->semaphore);
2091 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2102 clone_image=(*image);
2103 clone_image.semaphore=AllocateSemaphoreInfo();
2104 clone_image.reference_count=1;
2105 clone_image.cache=ClonePixelCache(cache_info);
2106 clone_info=(CacheInfo *) clone_image.cache;
2107 status=OpenPixelCache(&clone_image,IOMode,exception);
2108 if (status != MagickFalse)
2110 if (clone != MagickFalse)
2111 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2112 if (status != MagickFalse)
2114 if (cache_info->mode == ReadMode)
2115 cache_info->nexus_info=(NexusInfo **) NULL;
2117 image->cache=clone_image.cache;
2120 DestroySemaphoreInfo(&clone_image.semaphore);
2122 UnlockSemaphoreInfo(cache_info->semaphore);
2124 if (destroy != MagickFalse)
2125 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2126 if (status != MagickFalse)
2129 Ensure the image matches the pixel cache morphology.
2131 image->taint=MagickTrue;
2132 image->type=UndefinedType;
2133 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2134 status=OpenPixelCache(image,IOMode,exception);
2136 UnlockSemaphoreInfo(image->semaphore);
2137 if (status == MagickFalse)
2138 return((Cache) NULL);
2139 return(image->cache);
2143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2147 % G e t O n e A u t h e n t i c P i x e l %
2151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2153 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2154 % location. The image background color is returned if an error occurs.
2156 % The format of the GetOneAuthenticPixel() method is:
2158 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2159 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2161 % A description of each parameter follows:
2163 % o image: the image.
2165 % o x,y: These values define the location of the pixel to return.
2167 % o pixel: return a pixel at the specified (x,y) location.
2169 % o exception: return any errors or warnings in this structure.
2172 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2173 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2184 assert(image != (Image *) NULL);
2185 assert(image->signature == MagickSignature);
2186 assert(image->cache != (Cache) NULL);
2187 cache_info=(CacheInfo *) image->cache;
2188 assert(cache_info->signature == MagickSignature);
2189 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2190 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2191 (GetOneAuthenticPixelFromHandler) NULL)
2192 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2194 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2195 if (q == (Quantum *) NULL)
2197 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2198 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2199 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2200 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2201 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2202 return(MagickFalse);
2204 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2209 channel=GetPixelChannelMapChannel(image,i);
2210 pixel[channel]=q[i];
2216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2220 + 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 %
2224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2226 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2227 % location. The image background color is returned if an error occurs.
2229 % The format of the GetOneAuthenticPixelFromCache() method is:
2231 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2232 % const ssize_t x,const ssize_t y,Quantum *pixel,
2233 % ExceptionInfo *exception)
2235 % A description of each parameter follows:
2237 % o image: the image.
2239 % o x,y: These values define the location of the pixel to return.
2241 % o pixel: return a pixel at the specified (x,y) location.
2243 % o exception: return any errors or warnings in this structure.
2246 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2247 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2253 id = GetOpenMPThreadId();
2261 assert(image != (const Image *) NULL);
2262 assert(image->signature == MagickSignature);
2263 assert(image->cache != (Cache) NULL);
2264 cache_info=(CacheInfo *) image->cache;
2265 assert(cache_info->signature == MagickSignature);
2266 assert(id < (int) cache_info->number_threads);
2267 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2268 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2270 if (q == (Quantum *) NULL)
2272 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2273 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2274 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2275 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2276 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2277 return(MagickFalse);
2279 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2284 channel=GetPixelChannelMapChannel(image,i);
2285 pixel[channel]=q[i];
2291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2295 % G e t O n e V i r t u a l P i x e l %
2299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2301 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2302 % (x,y) location. The image background color is returned if an error occurs.
2303 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2305 % The format of the GetOneVirtualPixel() method is:
2307 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2308 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2310 % A description of each parameter follows:
2312 % o image: the image.
2314 % o x,y: These values define the location of the pixel to return.
2316 % o pixel: return a pixel at the specified (x,y) location.
2318 % o exception: return any errors or warnings in this structure.
2321 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2322 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2328 id = GetOpenMPThreadId();
2336 assert(image != (const Image *) NULL);
2337 assert(image->signature == MagickSignature);
2338 assert(image->cache != (Cache) NULL);
2339 cache_info=(CacheInfo *) image->cache;
2340 assert(cache_info->signature == MagickSignature);
2341 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2342 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2343 (GetOneVirtualPixelFromHandler) NULL)
2344 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2345 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2346 assert(id < (int) cache_info->number_threads);
2347 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2348 1UL,1UL,cache_info->nexus_info[id],exception);
2349 if (p == (const Quantum *) NULL)
2351 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2352 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2353 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2354 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2355 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2356 return(MagickFalse);
2358 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2363 channel=GetPixelChannelMapChannel(image,i);
2364 pixel[channel]=p[i];
2370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2374 + 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 %
2378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2380 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2381 % specified (x,y) location. The image background color is returned if an
2384 % The format of the GetOneVirtualPixelFromCache() method is:
2386 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2387 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2388 % Quantum *pixel,ExceptionInfo *exception)
2390 % A description of each parameter follows:
2392 % o image: the image.
2394 % o virtual_pixel_method: the virtual pixel method.
2396 % o x,y: These values define the location of the pixel to return.
2398 % o pixel: return a pixel at the specified (x,y) location.
2400 % o exception: return any errors or warnings in this structure.
2403 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2404 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2405 Quantum *pixel,ExceptionInfo *exception)
2411 id = GetOpenMPThreadId();
2419 assert(image != (const Image *) NULL);
2420 assert(image->signature == MagickSignature);
2421 assert(image->cache != (Cache) NULL);
2422 cache_info=(CacheInfo *) image->cache;
2423 assert(cache_info->signature == MagickSignature);
2424 assert(id < (int) cache_info->number_threads);
2425 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2426 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2427 cache_info->nexus_info[id],exception);
2428 if (p == (const Quantum *) NULL)
2430 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2431 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2432 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2433 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2434 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2435 return(MagickFalse);
2437 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2442 channel=GetPixelChannelMapChannel(image,i);
2443 pixel[channel]=p[i];
2449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2453 % G e t O n e V i r t u a l P i x e l I n f o %
2457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2459 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2460 % location. The image background color is returned if an error occurs. If
2461 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2463 % The format of the GetOneVirtualPixelInfo() method is:
2465 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2466 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2467 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2469 % A description of each parameter follows:
2471 % o image: the image.
2473 % o virtual_pixel_method: the virtual pixel method.
2475 % o x,y: these values define the location of the pixel to return.
2477 % o pixel: return a pixel at the specified (x,y) location.
2479 % o exception: return any errors or warnings in this structure.
2482 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2483 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2484 PixelInfo *pixel,ExceptionInfo *exception)
2490 id = GetOpenMPThreadId();
2492 register const Quantum
2495 assert(image != (const Image *) NULL);
2496 assert(image->signature == MagickSignature);
2497 assert(image->cache != (Cache) NULL);
2498 cache_info=(CacheInfo *) image->cache;
2499 assert(cache_info->signature == MagickSignature);
2500 assert(id < (int) cache_info->number_threads);
2501 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2502 cache_info->nexus_info[id],exception);
2503 GetPixelInfo(image,pixel);
2504 if (p == (const Quantum *) NULL)
2505 return(MagickFalse);
2506 GetPixelInfoPixel(image,p,pixel);
2511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2515 + G e t P i x e l C a c h e C o l o r s p a c e %
2519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2521 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2523 % The format of the GetPixelCacheColorspace() method is:
2525 % Colorspace GetPixelCacheColorspace(Cache cache)
2527 % A description of each parameter follows:
2529 % o cache: the pixel cache.
2532 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2537 assert(cache != (Cache) NULL);
2538 cache_info=(CacheInfo *) cache;
2539 assert(cache_info->signature == MagickSignature);
2540 if (cache_info->debug != MagickFalse)
2541 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2542 cache_info->filename);
2543 return(cache_info->colorspace);
2547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2551 + G e t P i x e l C a c h e M e t h o d s %
2555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2557 % GetPixelCacheMethods() initializes the CacheMethods structure.
2559 % The format of the GetPixelCacheMethods() method is:
2561 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2563 % A description of each parameter follows:
2565 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2568 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2570 assert(cache_methods != (CacheMethods *) NULL);
2571 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2572 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2573 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2574 cache_methods->get_virtual_metacontent_from_handler=
2575 GetVirtualMetacontentFromCache;
2576 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2577 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2578 cache_methods->get_authentic_metacontent_from_handler=
2579 GetAuthenticMetacontentFromCache;
2580 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2581 cache_methods->get_one_authentic_pixel_from_handler=
2582 GetOneAuthenticPixelFromCache;
2583 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2584 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2585 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2593 + G e t P i x e l C a c h e N e x u s E x t e n t %
2597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2599 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2600 % corresponding with the last call to SetPixelCacheNexusPixels() or
2601 % GetPixelCacheNexusPixels().
2603 % The format of the GetPixelCacheNexusExtent() method is:
2605 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2606 % NexusInfo *nexus_info)
2608 % A description of each parameter follows:
2610 % o nexus_info: the nexus info.
2613 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2614 NexusInfo *nexus_info)
2622 assert(cache != NULL);
2623 cache_info=(CacheInfo *) cache;
2624 assert(cache_info->signature == MagickSignature);
2625 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2627 return((MagickSizeType) cache_info->columns*cache_info->rows);
2632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2636 + 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 %
2640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2642 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2645 % The format of the GetPixelCacheNexusMetacontent() method is:
2647 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2648 % NexusInfo *nexus_info)
2650 % A description of each parameter follows:
2652 % o cache: the pixel cache.
2654 % o nexus_info: the cache nexus to return the meta-content.
2657 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2658 NexusInfo *nexus_info)
2663 assert(cache != NULL);
2664 cache_info=(CacheInfo *) cache;
2665 assert(cache_info->signature == MagickSignature);
2666 if (cache_info->storage_class == UndefinedClass)
2667 return((void *) NULL);
2668 return(nexus_info->metacontent);
2672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2676 + G e t P i x e l C a c h e N e x u s P i x e l s %
2680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2682 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2685 % The format of the GetPixelCacheNexusPixels() method is:
2687 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2688 % NexusInfo *nexus_info)
2690 % A description of each parameter follows:
2692 % o cache: the pixel cache.
2694 % o nexus_info: the cache nexus to return the pixels.
2697 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2698 NexusInfo *nexus_info)
2703 assert(cache != NULL);
2704 cache_info=(CacheInfo *) cache;
2705 assert(cache_info->signature == MagickSignature);
2706 if (cache_info->storage_class == UndefinedClass)
2707 return((Quantum *) NULL);
2708 return(nexus_info->pixels);
2712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2716 + G e t P i x e l C a c h e P i x e l s %
2720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2722 % GetPixelCachePixels() returns the pixels associated with the specified image.
2724 % The format of the GetPixelCachePixels() method is:
2726 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2727 % ExceptionInfo *exception)
2729 % A description of each parameter follows:
2731 % o image: the image.
2733 % o length: the pixel cache length.
2735 % o exception: return any errors or warnings in this structure.
2738 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2739 ExceptionInfo *exception)
2744 assert(image != (const Image *) NULL);
2745 assert(image->signature == MagickSignature);
2746 assert(image->cache != (Cache) NULL);
2747 assert(length != (MagickSizeType *) NULL);
2748 assert(exception != (ExceptionInfo *) NULL);
2749 assert(exception->signature == MagickSignature);
2750 cache_info=(CacheInfo *) image->cache;
2751 assert(cache_info->signature == MagickSignature);
2753 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2754 return((void *) NULL);
2755 *length=cache_info->length;
2756 return((void *) cache_info->pixels);
2760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2764 + 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 %
2768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2770 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2772 % The format of the GetPixelCacheStorageClass() method is:
2774 % ClassType GetPixelCacheStorageClass(Cache cache)
2776 % A description of each parameter follows:
2778 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2780 % o cache: the pixel cache.
2783 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2788 assert(cache != (Cache) NULL);
2789 cache_info=(CacheInfo *) cache;
2790 assert(cache_info->signature == MagickSignature);
2791 if (cache_info->debug != MagickFalse)
2792 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2793 cache_info->filename);
2794 return(cache_info->storage_class);
2798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802 + G e t P i x e l C a c h e T i l e S i z e %
2806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2808 % GetPixelCacheTileSize() returns the pixel cache tile size.
2810 % The format of the GetPixelCacheTileSize() method is:
2812 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2815 % A description of each parameter follows:
2817 % o image: the image.
2819 % o width: the optimize cache tile width in pixels.
2821 % o height: the optimize cache tile height in pixels.
2824 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2830 assert(image != (Image *) NULL);
2831 assert(image->signature == MagickSignature);
2832 if (image->debug != MagickFalse)
2833 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2834 cache_info=(CacheInfo *) image->cache;
2835 assert(cache_info->signature == MagickSignature);
2836 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2837 if (GetPixelCacheType(image) == DiskCache)
2838 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847 + G e t P i x e l C a c h e T y p e %
2851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2853 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2855 % The format of the GetPixelCacheType() method is:
2857 % CacheType GetPixelCacheType(const Image *image)
2859 % A description of each parameter follows:
2861 % o image: the image.
2864 MagickPrivate CacheType GetPixelCacheType(const Image *image)
2869 assert(image != (Image *) NULL);
2870 assert(image->signature == MagickSignature);
2871 assert(image->cache != (Cache) NULL);
2872 cache_info=(CacheInfo *) image->cache;
2873 assert(cache_info->signature == MagickSignature);
2874 return(cache_info->type);
2878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2882 + 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 %
2886 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2888 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2889 % pixel cache. A virtual pixel is any pixel access that is outside the
2890 % boundaries of the image cache.
2892 % The format of the GetPixelCacheVirtualMethod() method is:
2894 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2896 % A description of each parameter follows:
2898 % o image: the image.
2901 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2906 assert(image != (Image *) NULL);
2907 assert(image->signature == MagickSignature);
2908 assert(image->cache != (Cache) NULL);
2909 cache_info=(CacheInfo *) image->cache;
2910 assert(cache_info->signature == MagickSignature);
2911 return(cache_info->virtual_pixel_method);
2915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2919 + 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 %
2923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2925 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2926 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2928 % The format of the GetVirtualMetacontentFromCache() method is:
2930 % void *GetVirtualMetacontentFromCache(const Image *image)
2932 % A description of each parameter follows:
2934 % o image: the image.
2937 static const void *GetVirtualMetacontentFromCache(const Image *image)
2943 id = GetOpenMPThreadId();
2948 assert(image != (const Image *) NULL);
2949 assert(image->signature == MagickSignature);
2950 assert(image->cache != (Cache) NULL);
2951 cache_info=(CacheInfo *) image->cache;
2952 assert(cache_info->signature == MagickSignature);
2953 assert(id < (int) cache_info->number_threads);
2954 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2955 cache_info->nexus_info[id]);
2956 return(metacontent);
2960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2964 + 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 %
2968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2970 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2973 % The format of the GetVirtualMetacontentFromNexus() method is:
2975 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2976 % NexusInfo *nexus_info)
2978 % A description of each parameter follows:
2980 % o cache: the pixel cache.
2982 % o nexus_info: the cache nexus to return the meta-content.
2985 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2986 NexusInfo *nexus_info)
2991 assert(cache != (Cache) NULL);
2992 cache_info=(CacheInfo *) cache;
2993 assert(cache_info->signature == MagickSignature);
2994 if (cache_info->storage_class == UndefinedClass)
2995 return((void *) NULL);
2996 return(nexus_info->metacontent);
3000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3004 % G e t V i r t u a l M e t a c o n t e n t %
3008 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3010 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
3011 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3012 % returned if the meta-content are not available.
3014 % The format of the GetVirtualMetacontent() method is:
3016 % const void *GetVirtualMetacontent(const Image *image)
3018 % A description of each parameter follows:
3020 % o image: the image.
3023 MagickExport const void *GetVirtualMetacontent(const Image *image)
3029 id = GetOpenMPThreadId();
3034 assert(image != (const Image *) NULL);
3035 assert(image->signature == MagickSignature);
3036 assert(image->cache != (Cache) NULL);
3037 cache_info=(CacheInfo *) image->cache;
3038 assert(cache_info->signature == MagickSignature);
3039 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3040 (GetVirtualMetacontentFromHandler) NULL)
3042 metacontent=cache_info->methods.
3043 get_virtual_metacontent_from_handler(image);
3044 return(metacontent);
3046 assert(id < (int) cache_info->number_threads);
3047 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3048 cache_info->nexus_info[id]);
3049 return(metacontent);
3053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3057 + 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 %
3061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3063 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3064 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3065 % is returned if the pixels are transferred, otherwise a NULL is returned.
3067 % The format of the GetVirtualPixelsFromNexus() method is:
3069 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
3070 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3071 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
3072 % ExceptionInfo *exception)
3074 % A description of each parameter follows:
3076 % o image: the image.
3078 % o virtual_pixel_method: the virtual pixel method.
3080 % o x,y,columns,rows: These values define the perimeter of a region of
3083 % o nexus_info: the cache nexus to acquire.
3085 % o exception: return any errors or warnings in this structure.
3092 0, 48, 12, 60, 3, 51, 15, 63,
3093 32, 16, 44, 28, 35, 19, 47, 31,
3094 8, 56, 4, 52, 11, 59, 7, 55,
3095 40, 24, 36, 20, 43, 27, 39, 23,
3096 2, 50, 14, 62, 1, 49, 13, 61,
3097 34, 18, 46, 30, 33, 17, 45, 29,
3098 10, 58, 6, 54, 9, 57, 5, 53,
3099 42, 26, 38, 22, 41, 25, 37, 21
3102 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3107 index=x+DitherMatrix[x & 0x07]-32L;
3110 if (index >= (ssize_t) columns)
3111 return((ssize_t) columns-1L);
3115 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3120 index=y+DitherMatrix[y & 0x07]-32L;
3123 if (index >= (ssize_t) rows)
3124 return((ssize_t) rows-1L);
3128 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3132 if (x >= (ssize_t) columns)
3133 return((ssize_t) (columns-1));
3137 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3141 if (y >= (ssize_t) rows)
3142 return((ssize_t) (rows-1));
3146 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3148 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3151 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3153 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3156 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3157 const size_t extent)
3163 Compute the remainder of dividing offset by extent. It returns not only
3164 the quotient (tile the offset falls in) but also the positive remainer
3165 within that tile such that 0 <= remainder < extent. This method is
3166 essentially a ldiv() using a floored modulo division rather than the
3167 normal default truncated modulo division.
3169 modulo.quotient=offset/(ssize_t) extent;
3172 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3176 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3177 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3178 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3179 ExceptionInfo *exception)
3196 virtual_pixel[CompositePixelChannel];
3201 register const Quantum
3214 register unsigned char
3221 *virtual_metacontent;
3226 assert(image != (const Image *) NULL);
3227 assert(image->signature == MagickSignature);
3228 assert(image->cache != (Cache) NULL);
3229 cache_info=(CacheInfo *) image->cache;
3230 assert(cache_info->signature == MagickSignature);
3231 if (cache_info->type == UndefinedCache)
3232 return((const Quantum *) NULL);
3235 region.width=columns;
3237 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3238 if (pixels == (Quantum *) NULL)
3239 return((const Quantum *) NULL);
3241 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3242 nexus_info->region.x;
3243 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3244 nexus_info->region.width-1L;
3245 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3246 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3247 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3248 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3254 Pixel request is inside cache extents.
3256 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3258 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3259 if (status == MagickFalse)
3260 return((const Quantum *) NULL);
3261 if (cache_info->metacontent_extent != 0)
3263 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3264 if (status == MagickFalse)
3265 return((const Quantum *) NULL);
3270 Pixel request is outside cache extents.
3272 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3273 virtual_nexus=AcquirePixelCacheNexus(1);
3274 if (virtual_nexus == (NexusInfo **) NULL)
3276 if (virtual_nexus != (NexusInfo **) NULL)
3277 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3278 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3279 "UnableToGetCacheNexus","`%s'",image->filename);
3280 return((const Quantum *) NULL);
3282 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3283 sizeof(*virtual_pixel));
3284 virtual_metacontent=(void *) NULL;
3285 switch (virtual_pixel_method)
3287 case BackgroundVirtualPixelMethod:
3288 case BlackVirtualPixelMethod:
3289 case GrayVirtualPixelMethod:
3290 case TransparentVirtualPixelMethod:
3291 case MaskVirtualPixelMethod:
3292 case WhiteVirtualPixelMethod:
3293 case EdgeVirtualPixelMethod:
3294 case CheckerTileVirtualPixelMethod:
3295 case HorizontalTileVirtualPixelMethod:
3296 case VerticalTileVirtualPixelMethod:
3298 if (cache_info->metacontent_extent != 0)
3301 Acquire a metacontent buffer.
3303 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3304 cache_info->metacontent_extent);
3305 if (virtual_metacontent == (void *) NULL)
3307 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3308 (void) ThrowMagickException(exception,GetMagickModule(),
3309 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3310 return((const Quantum *) NULL);
3312 (void) ResetMagickMemory(virtual_metacontent,0,
3313 cache_info->metacontent_extent);
3315 switch (virtual_pixel_method)
3317 case BlackVirtualPixelMethod:
3319 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3320 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3321 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3324 case GrayVirtualPixelMethod:
3326 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3327 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3329 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3332 case TransparentVirtualPixelMethod:
3334 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3335 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3336 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3339 case MaskVirtualPixelMethod:
3340 case WhiteVirtualPixelMethod:
3342 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3343 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3344 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3349 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3351 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3353 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3355 if (image->colorspace == CMYKColorspace)
3356 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3358 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3368 for (v=0; v < (ssize_t) rows; v++)
3370 for (u=0; u < (ssize_t) columns; u+=length)
3372 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3373 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3374 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3382 Transfer a single pixel.
3384 length=(MagickSizeType) 1;
3385 switch (virtual_pixel_method)
3389 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3390 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3391 1UL,1UL,*virtual_nexus,exception);
3392 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3395 case RandomVirtualPixelMethod:
3397 if (cache_info->random_info == (RandomInfo *) NULL)
3398 cache_info->random_info=AcquireRandomInfo();
3399 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3400 RandomX(cache_info->random_info,cache_info->columns),
3401 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3402 *virtual_nexus,exception);
3403 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3406 case DitherVirtualPixelMethod:
3408 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3409 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3410 1UL,1UL,*virtual_nexus,exception);
3411 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3414 case TileVirtualPixelMethod:
3416 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3417 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3418 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3419 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3421 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3424 case MirrorVirtualPixelMethod:
3426 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3427 if ((x_modulo.quotient & 0x01) == 1L)
3428 x_modulo.remainder=(ssize_t) cache_info->columns-
3429 x_modulo.remainder-1L;
3430 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3431 if ((y_modulo.quotient & 0x01) == 1L)
3432 y_modulo.remainder=(ssize_t) cache_info->rows-
3433 y_modulo.remainder-1L;
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 HorizontalTileEdgeVirtualPixelMethod:
3442 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3443 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3444 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3445 *virtual_nexus,exception);
3446 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3449 case VerticalTileEdgeVirtualPixelMethod:
3451 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3452 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3453 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3454 *virtual_nexus,exception);
3455 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3458 case BackgroundVirtualPixelMethod:
3459 case BlackVirtualPixelMethod:
3460 case GrayVirtualPixelMethod:
3461 case TransparentVirtualPixelMethod:
3462 case MaskVirtualPixelMethod:
3463 case WhiteVirtualPixelMethod:
3466 r=virtual_metacontent;
3469 case EdgeVirtualPixelMethod:
3470 case CheckerTileVirtualPixelMethod:
3472 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3473 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3474 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3477 r=virtual_metacontent;
3480 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3481 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3483 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3486 case HorizontalTileVirtualPixelMethod:
3488 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3491 r=virtual_metacontent;
3494 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3495 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3496 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3497 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3499 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3502 case VerticalTileVirtualPixelMethod:
3504 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3507 r=virtual_metacontent;
3510 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3511 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3512 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3513 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3515 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3519 if (p == (const Quantum *) NULL)
3521 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3523 q+=cache_info->number_channels;
3524 if ((s != (void *) NULL) && (r != (const void *) NULL))
3526 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3527 s+=cache_info->metacontent_extent;
3532 Transfer a run of pixels.
3534 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3535 length,1UL,*virtual_nexus,exception);
3536 if (p == (const Quantum *) NULL)
3538 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3539 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3540 q+=length*cache_info->number_channels;
3541 if ((r != (void *) NULL) && (s != (const void *) NULL))
3543 (void) memcpy(s,r,(size_t) length);
3544 s+=length*cache_info->metacontent_extent;
3551 if (virtual_metacontent != (void *) NULL)
3552 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3553 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3562 + G e t V i r t u a l P i x e l C a c h e %
3566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3568 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3569 % cache as defined by the geometry parameters. A pointer to the pixels
3570 % is returned if the pixels are transferred, otherwise a NULL is returned.
3572 % The format of the GetVirtualPixelCache() method is:
3574 % const Quantum *GetVirtualPixelCache(const Image *image,
3575 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3576 % const ssize_t y,const size_t columns,const size_t rows,
3577 % ExceptionInfo *exception)
3579 % A description of each parameter follows:
3581 % o image: the image.
3583 % o virtual_pixel_method: the virtual pixel method.
3585 % o x,y,columns,rows: These values define the perimeter of a region of
3588 % o exception: return any errors or warnings in this structure.
3591 static const Quantum *GetVirtualPixelCache(const Image *image,
3592 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3593 const size_t columns,const size_t rows,ExceptionInfo *exception)
3599 id = GetOpenMPThreadId();
3604 assert(image != (const Image *) NULL);
3605 assert(image->signature == MagickSignature);
3606 assert(image->cache != (Cache) NULL);
3607 cache_info=(CacheInfo *) image->cache;
3608 assert(cache_info->signature == MagickSignature);
3609 assert(id < (int) cache_info->number_threads);
3610 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3611 cache_info->nexus_info[id],exception);
3616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3620 % G e t V i r t u a l P i x e l Q u e u e %
3624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3626 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3627 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3629 % The format of the GetVirtualPixelQueue() method is:
3631 % const Quantum *GetVirtualPixelQueue(const Image image)
3633 % A description of each parameter follows:
3635 % o image: the image.
3638 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3644 id = GetOpenMPThreadId();
3646 assert(image != (const Image *) NULL);
3647 assert(image->signature == MagickSignature);
3648 assert(image->cache != (Cache) NULL);
3649 cache_info=(CacheInfo *) image->cache;
3650 assert(cache_info->signature == MagickSignature);
3651 if (cache_info->methods.get_virtual_pixels_handler !=
3652 (GetVirtualPixelsHandler) NULL)
3653 return(cache_info->methods.get_virtual_pixels_handler(image));
3654 assert(id < (int) cache_info->number_threads);
3655 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3659 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3663 % G e t V i r t u a l P i x e l s %
3667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3669 % GetVirtualPixels() returns an immutable pixel region. If the
3670 % region is successfully accessed, a pointer to it is returned, otherwise
3671 % NULL is returned. The returned pointer may point to a temporary working
3672 % copy of the pixels or it may point to the original pixels in memory.
3673 % Performance is maximized if the selected region is part of one row, or one
3674 % or more full rows, since there is opportunity to access the pixels in-place
3675 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3676 % returned pointer must *never* be deallocated by the user.
3678 % Pixels accessed via the returned pointer represent a simple array of type
3679 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3680 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3681 % access the meta-content (of type void) corresponding to the the
3684 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3686 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3687 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3688 % GetCacheViewAuthenticPixels() instead.
3690 % The format of the GetVirtualPixels() method is:
3692 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3693 % const ssize_t y,const size_t columns,const size_t rows,
3694 % ExceptionInfo *exception)
3696 % A description of each parameter follows:
3698 % o image: the image.
3700 % o x,y,columns,rows: These values define the perimeter of a region of
3703 % o exception: return any errors or warnings in this structure.
3706 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3707 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3708 ExceptionInfo *exception)
3714 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 if (cache_info->methods.get_virtual_pixel_handler !=
3725 (GetVirtualPixelHandler) NULL)
3726 return(cache_info->methods.get_virtual_pixel_handler(image,
3727 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3728 assert(id < (int) cache_info->number_threads);
3729 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3730 columns,rows,cache_info->nexus_info[id],exception);
3735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3739 + 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 %
3743 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3745 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3746 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3748 % The format of the GetVirtualPixelsCache() method is:
3750 % Quantum *GetVirtualPixelsCache(const Image *image)
3752 % A description of each parameter follows:
3754 % o image: the image.
3757 static const Quantum *GetVirtualPixelsCache(const Image *image)
3763 id = GetOpenMPThreadId();
3765 assert(image != (const Image *) NULL);
3766 assert(image->signature == MagickSignature);
3767 assert(image->cache != (Cache) NULL);
3768 cache_info=(CacheInfo *) image->cache;
3769 assert(cache_info->signature == MagickSignature);
3770 assert(id < (int) cache_info->number_threads);
3771 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3779 + G e t V i r t u a l P i x e l s N e x u s %
3783 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3785 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3788 % The format of the GetVirtualPixelsNexus() method is:
3790 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3791 % NexusInfo *nexus_info)
3793 % A description of each parameter follows:
3795 % o cache: the pixel cache.
3797 % o nexus_info: the cache nexus to return the colormap pixels.
3800 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3801 NexusInfo *nexus_info)
3806 assert(cache != (Cache) NULL);
3807 cache_info=(CacheInfo *) cache;
3808 assert(cache_info->signature == MagickSignature);
3809 if (cache_info->storage_class == UndefinedClass)
3810 return((Quantum *) NULL);
3811 return((const Quantum *) nexus_info->pixels);
3815 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3819 + M a s k P i x e l C a c h e N e x u s %
3823 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3825 % MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3826 % The method returns MagickTrue if the pixel region is masked, otherwise
3829 % The format of the MaskPixelCacheNexus() method is:
3831 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3832 % NexusInfo *nexus_info,ExceptionInfo *exception)
3834 % A description of each parameter follows:
3836 % o image: the image.
3838 % o nexus_info: the cache nexus to clip.
3840 % o exception: return any errors or warnings in this structure.
3844 static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3845 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
3850 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
3855 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3856 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3857 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3858 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3859 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3860 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3861 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
3864 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3865 ExceptionInfo *exception)
3881 register const Quantum
3894 if (image->debug != MagickFalse)
3895 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3896 if (image->mask == (Image *) NULL)
3897 return(MagickFalse);
3898 cache_info=(CacheInfo *) image->cache;
3899 if (cache_info == (Cache) NULL)
3900 return(MagickFalse);
3901 image_nexus=AcquirePixelCacheNexus(1);
3902 clip_nexus=AcquirePixelCacheNexus(1);
3903 if ((image_nexus == (NexusInfo **) NULL) ||
3904 (clip_nexus == (NexusInfo **) NULL))
3905 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3906 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3907 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3908 nexus_info->region.height,image_nexus[0],exception);
3909 q=nexus_info->pixels;
3910 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3911 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3912 nexus_info->region.height,clip_nexus[0],exception);
3913 GetPixelInfo(image,&alpha);
3914 GetPixelInfo(image,&beta);
3915 number_pixels=(MagickSizeType) nexus_info->region.width*
3916 nexus_info->region.height;
3917 for (i=0; i < (ssize_t) number_pixels; i++)
3919 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
3921 GetPixelInfoPixel(image,p,&alpha);
3922 GetPixelInfoPixel(image,q,&beta);
3923 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
3924 &alpha,alpha.alpha,&beta);
3925 SetPixelRed(image,ClampToQuantum(beta.red),q);
3926 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3927 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3928 if (cache_info->colorspace == CMYKColorspace)
3929 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3930 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
3935 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3936 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3937 if (i < (ssize_t) number_pixels)
3938 return(MagickFalse);
3943 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3947 + O p e n P i x e l C a c h e %
3951 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3953 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3954 % dimensions, allocating space for the image pixels and optionally the
3955 % metacontent, and memory mapping the cache if it is disk based. The cache
3956 % nexus array is initialized as well.
3958 % The format of the OpenPixelCache() method is:
3960 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3961 % ExceptionInfo *exception)
3963 % A description of each parameter follows:
3965 % o image: the image.
3967 % o mode: ReadMode, WriteMode, or IOMode.
3969 % o exception: return any errors or warnings in this structure.
3973 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3975 cache_info->mapped=MagickFalse;
3976 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3977 cache_info->length);
3978 if (cache_info->pixels == (Quantum *) NULL)
3980 cache_info->mapped=MagickTrue;
3981 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3982 cache_info->length);
3986 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3996 cache_info=(CacheInfo *) image->cache;
3997 if (image->debug != MagickFalse)
4000 format[MaxTextExtent],
4001 message[MaxTextExtent];
4003 (void) FormatMagickSize(length,MagickFalse,format);
4004 (void) FormatLocaleString(message,MaxTextExtent,
4005 "extend %s (%s[%d], disk, %s)",cache_info->filename,
4006 cache_info->cache_filename,cache_info->file,format);
4007 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4009 if (length != (MagickSizeType) ((MagickOffsetType) length))
4010 return(MagickFalse);
4011 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
4013 return(MagickFalse);
4014 if ((MagickSizeType) extent >= length)
4016 offset=(MagickOffsetType) length-1;
4017 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4018 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4021 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4022 ExceptionInfo *exception)
4029 format[MaxTextExtent],
4030 message[MaxTextExtent];
4047 assert(image != (const Image *) NULL);
4048 assert(image->signature == MagickSignature);
4049 assert(image->cache != (Cache) NULL);
4050 if (image->debug != MagickFalse)
4051 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4052 if ((image->columns == 0) || (image->rows == 0))
4053 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4054 cache_info=(CacheInfo *) image->cache;
4055 assert(cache_info->signature == MagickSignature);
4056 source_info=(*cache_info);
4057 source_info.file=(-1);
4058 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4059 image->filename,(double) GetImageIndexInList(image));
4060 cache_info->storage_class=image->storage_class;
4061 cache_info->colorspace=image->colorspace;
4062 cache_info->matte=image->matte;
4063 cache_info->rows=image->rows;
4064 cache_info->columns=image->columns;
4065 InitializePixelChannelMap(image);
4066 cache_info->number_channels=GetPixelChannels(image);
4067 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4068 sizeof(*image->channel_map));
4069 cache_info->metacontent_extent=image->metacontent_extent;
4070 cache_info->mode=mode;
4071 if (image->ping != MagickFalse)
4073 cache_info->type=PingCache;
4074 cache_info->pixels=(Quantum *) NULL;
4075 cache_info->metacontent=(void *) NULL;
4076 cache_info->length=0;
4079 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4080 packet_size=cache_info->number_channels*sizeof(Quantum);
4081 if (image->metacontent_extent != 0)
4082 packet_size+=cache_info->metacontent_extent;
4083 length=number_pixels*packet_size;
4084 columns=(size_t) (length/cache_info->rows/packet_size);
4085 if (cache_info->columns != columns)
4086 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4088 cache_info->length=length;
4089 p=cache_info->channel_map;
4090 q=source_info.channel_map;
4091 if ((cache_info->type != UndefinedCache) &&
4092 (cache_info->columns <= source_info.columns) &&
4093 (cache_info->rows <= source_info.rows) &&
4094 (cache_info->number_channels <= source_info.number_channels) &&
4095 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
4096 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4099 Inline pixel cache clone optimization.
4101 if ((cache_info->columns == source_info.columns) &&
4102 (cache_info->rows == source_info.rows) &&
4103 (cache_info->number_channels == source_info.number_channels) &&
4104 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
4105 (cache_info->metacontent_extent == source_info.metacontent_extent))
4107 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4109 status=AcquireMagickResource(AreaResource,cache_info->length);
4110 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4111 cache_info->metacontent_extent);
4112 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4114 status=AcquireMagickResource(MemoryResource,cache_info->length);
4115 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4116 (cache_info->type == MemoryCache))
4118 AllocatePixelCachePixels(cache_info);
4119 if (cache_info->pixels == (Quantum *) NULL)
4120 cache_info->pixels=source_info.pixels;
4124 Create memory pixel cache.
4127 if (image->debug != MagickFalse)
4129 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
4130 (void) FormatLocaleString(message,MaxTextExtent,
4131 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4132 cache_info->filename,cache_info->mapped != MagickFalse ?
4133 "anonymous" : "heap",(double) cache_info->columns,(double)
4134 cache_info->rows,(double) cache_info->number_channels,
4136 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4139 cache_info->type=MemoryCache;
4140 cache_info->metacontent=(void *) NULL;
4141 if (cache_info->metacontent_extent != 0)
4142 cache_info->metacontent=(void *) (cache_info->pixels+
4143 number_pixels*cache_info->number_channels);
4144 if (source_info.type != UndefinedCache)
4146 status=ClonePixelCachePixels(cache_info,&source_info,
4148 RelinquishPixelCachePixels(&source_info);
4153 RelinquishMagickResource(MemoryResource,cache_info->length);
4156 Create pixel cache on disk.
4158 status=AcquireMagickResource(DiskResource,cache_info->length);
4159 if (status == MagickFalse)
4161 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4162 "CacheResourcesExhausted","`%s'",image->filename);
4163 return(MagickFalse);
4165 if (source_info.type != UndefinedCache)
4166 *cache_info->cache_filename='\0';
4167 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4169 RelinquishMagickResource(DiskResource,cache_info->length);
4170 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4172 return(MagickFalse);
4174 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4175 cache_info->length);
4176 if (status == MagickFalse)
4178 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4180 return(MagickFalse);
4182 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4183 cache_info->metacontent_extent);
4184 if (length != (MagickSizeType) ((size_t) length))
4185 cache_info->type=DiskCache;
4188 status=AcquireMagickResource(MapResource,cache_info->length);
4189 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4190 (cache_info->type != MemoryCache))
4191 cache_info->type=DiskCache;
4194 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4195 cache_info->offset,(size_t) cache_info->length);
4196 if (cache_info->pixels == (Quantum *) NULL)
4198 cache_info->type=DiskCache;
4199 cache_info->pixels=source_info.pixels;
4204 Create file-backed memory-mapped pixel cache.
4207 (void) ClosePixelCacheOnDisk(cache_info);
4208 cache_info->type=MapCache;
4209 cache_info->mapped=MagickTrue;
4210 cache_info->metacontent=(void *) NULL;
4211 if (cache_info->metacontent_extent != 0)
4212 cache_info->metacontent=(void *) (cache_info->pixels+
4213 number_pixels*cache_info->number_channels);
4214 if (source_info.type != UndefinedCache)
4216 status=ClonePixelCachePixels(cache_info,&source_info,
4218 RelinquishPixelCachePixels(&source_info);
4220 if (image->debug != MagickFalse)
4222 (void) FormatMagickSize(cache_info->length,MagickTrue,
4224 (void) FormatLocaleString(message,MaxTextExtent,
4225 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4226 cache_info->filename,cache_info->cache_filename,
4227 cache_info->file,(double) cache_info->columns,(double)
4228 cache_info->rows,(double) cache_info->number_channels,
4230 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4236 RelinquishMagickResource(MapResource,cache_info->length);
4239 if (source_info.type != UndefinedCache)
4241 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4242 RelinquishPixelCachePixels(&source_info);
4244 if (image->debug != MagickFalse)
4246 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4247 (void) FormatLocaleString(message,MaxTextExtent,
4248 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4249 cache_info->cache_filename,cache_info->file,(double)
4250 cache_info->columns,(double) cache_info->rows,(double)
4251 cache_info->number_channels,format);
4252 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4262 + P e r s i s t P i x e l C a c h e %
4266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4268 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4269 % persistent pixel cache is one that resides on disk and is not destroyed
4270 % when the program exits.
4272 % The format of the PersistPixelCache() method is:
4274 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4275 % const MagickBooleanType attach,MagickOffsetType *offset,
4276 % ExceptionInfo *exception)
4278 % A description of each parameter follows:
4280 % o image: the image.
4282 % o filename: the persistent pixel cache filename.
4284 % o attach: A value other than zero initializes the persistent pixel cache.
4286 % o initialize: A value other than zero initializes the persistent pixel
4289 % o offset: the offset in the persistent cache to store pixels.
4291 % o exception: return any errors or warnings in this structure.
4294 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4295 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4296 ExceptionInfo *exception)
4311 assert(image != (Image *) NULL);
4312 assert(image->signature == MagickSignature);
4313 if (image->debug != MagickFalse)
4314 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4315 assert(image->cache != (void *) NULL);
4316 assert(filename != (const char *) NULL);
4317 assert(offset != (MagickOffsetType *) NULL);
4318 page_size=GetMagickPageSize();
4319 cache_info=(CacheInfo *) image->cache;
4320 assert(cache_info->signature == MagickSignature);
4321 if (attach != MagickFalse)
4324 Attach existing persistent pixel cache.
4326 if (image->debug != MagickFalse)
4327 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4328 "attach persistent cache");
4329 (void) CopyMagickString(cache_info->cache_filename,filename,
4331 cache_info->type=DiskCache;
4332 cache_info->offset=(*offset);
4333 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4334 return(MagickFalse);
4335 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4338 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4339 (cache_info->reference_count == 1))
4341 LockSemaphoreInfo(cache_info->semaphore);
4342 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4343 (cache_info->reference_count == 1))
4349 Usurp existing persistent pixel cache.
4351 status=rename_utf8(cache_info->cache_filename,filename);
4354 (void) CopyMagickString(cache_info->cache_filename,filename,
4356 *offset+=cache_info->length+page_size-(cache_info->length %
4358 UnlockSemaphoreInfo(cache_info->semaphore);
4359 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4360 if (image->debug != MagickFalse)
4361 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4362 "Usurp resident persistent cache");
4366 UnlockSemaphoreInfo(cache_info->semaphore);
4369 Clone persistent pixel cache.
4371 clone_image=(*image);
4372 clone_info=(CacheInfo *) clone_image.cache;
4373 image->cache=ClonePixelCache(cache_info);
4374 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4375 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4376 cache_info->type=DiskCache;
4377 cache_info->offset=(*offset);
4378 cache_info=(CacheInfo *) image->cache;
4379 status=OpenPixelCache(image,IOMode,exception);
4380 if (status != MagickFalse)
4381 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4382 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4383 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4392 + Q u e u e A u t h e n t i c N e x u s %
4396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4398 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4399 % by the region rectangle and returns a pointer to the region. This region is
4400 % subsequently transferred from the pixel cache with
4401 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4402 % pixels are transferred, otherwise a NULL is returned.
4404 % The format of the QueueAuthenticNexus() method is:
4406 % Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4407 % const ssize_t y,const size_t columns,const size_t rows,
4408 % const MagickBooleanType clone,NexusInfo *nexus_info,
4409 % ExceptionInfo *exception)
4411 % A description of each parameter follows:
4413 % o image: the image.
4415 % o x,y,columns,rows: These values define the perimeter of a region of
4418 % o nexus_info: the cache nexus to set.
4420 % o clone: clone the pixel cache.
4422 % o exception: return any errors or warnings in this structure.
4425 MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4426 const ssize_t y,const size_t columns,const size_t rows,
4427 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4442 Validate pixel cache geometry.
4444 assert(image != (const Image *) NULL);
4445 assert(image->signature == MagickSignature);
4446 assert(image->cache != (Cache) NULL);
4447 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4448 if (cache_info == (Cache) NULL)
4449 return((Quantum *) NULL);
4450 assert(cache_info->signature == MagickSignature);
4451 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4453 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4454 "NoPixelsDefinedInCache","`%s'",image->filename);
4455 return((Quantum *) NULL);
4457 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4458 (y >= (ssize_t) cache_info->rows))
4460 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4461 "PixelsAreNotAuthentic","`%s'",image->filename);
4462 return((Quantum *) NULL);
4464 offset=(MagickOffsetType) y*cache_info->columns+x;
4466 return((Quantum *) NULL);
4467 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4468 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4469 if ((MagickSizeType) offset >= number_pixels)
4470 return((Quantum *) NULL);
4476 region.width=columns;
4478 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4482 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4486 + 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 %
4490 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4492 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4493 % defined by the region rectangle and returns a pointer to the region. This
4494 % region is subsequently transferred from the pixel cache with
4495 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4496 % pixels are transferred, otherwise a NULL is returned.
4498 % The format of the QueueAuthenticPixelsCache() method is:
4500 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4501 % const ssize_t y,const size_t columns,const size_t rows,
4502 % ExceptionInfo *exception)
4504 % A description of each parameter follows:
4506 % o image: the image.
4508 % o x,y,columns,rows: These values define the perimeter of a region of
4511 % o exception: return any errors or warnings in this structure.
4514 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4515 const ssize_t y,const size_t columns,const size_t rows,
4516 ExceptionInfo *exception)
4522 id = GetOpenMPThreadId();
4527 assert(image != (const Image *) NULL);
4528 assert(image->signature == MagickSignature);
4529 assert(image->cache != (Cache) NULL);
4530 cache_info=(CacheInfo *) image->cache;
4531 assert(cache_info->signature == MagickSignature);
4532 assert(id < (int) cache_info->number_threads);
4533 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4534 cache_info->nexus_info[id],exception);
4539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4543 % Q u e u e A u t h e n t i c P i x e l s %
4547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4549 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4550 % successfully initialized a pointer to a Quantum array representing the
4551 % region is returned, otherwise NULL is returned. The returned pointer may
4552 % point to a temporary working buffer for the pixels or it may point to the
4553 % final location of the pixels in memory.
4555 % Write-only access means that any existing pixel values corresponding to
4556 % the region are ignored. This is useful if the initial image is being
4557 % created from scratch, or if the existing pixel values are to be
4558 % completely replaced without need to refer to their pre-existing values.
4559 % The application is free to read and write the pixel buffer returned by
4560 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4561 % initialize the pixel array values. Initializing pixel array values is the
4562 % application's responsibility.
4564 % Performance is maximized if the selected region is part of one row, or
4565 % one or more full rows, since then there is opportunity to access the
4566 % pixels in-place (without a copy) if the image is in memory, or in a
4567 % memory-mapped file. The returned pointer must *never* be deallocated
4570 % Pixels accessed via the returned pointer represent a simple array of type
4571 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4572 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4573 % obtain the meta-content (of type void) corresponding to the region.
4574 % Once the Quantum (and/or Quantum) array has been updated, the
4575 % changes must be saved back to the underlying image using
4576 % SyncAuthenticPixels() or they may be lost.
4578 % The format of the QueueAuthenticPixels() method is:
4580 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4581 % const ssize_t y,const size_t columns,const size_t rows,
4582 % ExceptionInfo *exception)
4584 % A description of each parameter follows:
4586 % o image: the image.
4588 % o x,y,columns,rows: These values define the perimeter of a region of
4591 % o exception: return any errors or warnings in this structure.
4594 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4595 const ssize_t y,const size_t columns,const size_t rows,
4596 ExceptionInfo *exception)
4602 id = GetOpenMPThreadId();
4607 assert(image != (Image *) NULL);
4608 assert(image->signature == MagickSignature);
4609 assert(image->cache != (Cache) NULL);
4610 cache_info=(CacheInfo *) image->cache;
4611 assert(cache_info->signature == MagickSignature);
4612 if (cache_info->methods.queue_authentic_pixels_handler !=
4613 (QueueAuthenticPixelsHandler) NULL)
4615 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4616 columns,rows,exception);
4619 assert(id < (int) cache_info->number_threads);
4620 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4621 cache_info->nexus_info[id],exception);
4626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4630 + 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 %
4634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4636 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4639 % The format of the ReadPixelCacheMetacontent() method is:
4641 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4642 % NexusInfo *nexus_info,ExceptionInfo *exception)
4644 % A description of each parameter follows:
4646 % o cache_info: the pixel cache.
4648 % o nexus_info: the cache nexus to read the metacontent.
4650 % o exception: return any errors or warnings in this structure.
4653 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4654 NexusInfo *nexus_info,ExceptionInfo *exception)
4667 register unsigned char
4673 if (cache_info->metacontent_extent == 0)
4674 return(MagickFalse);
4675 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4677 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4678 nexus_info->region.x;
4679 length=(MagickSizeType) nexus_info->region.width*
4680 cache_info->metacontent_extent;
4681 rows=nexus_info->region.height;
4683 q=(unsigned char *) nexus_info->metacontent;
4684 switch (cache_info->type)
4689 register unsigned char
4693 Read meta-content from memory.
4695 if ((cache_info->columns == nexus_info->region.width) &&
4696 (extent == (MagickSizeType) ((size_t) extent)))
4701 p=(unsigned char *) cache_info->metacontent+offset*
4702 cache_info->metacontent_extent;
4703 for (y=0; y < (ssize_t) rows; y++)
4705 (void) memcpy(q,p,(size_t) length);
4706 p+=cache_info->metacontent_extent*cache_info->columns;
4707 q+=cache_info->metacontent_extent*nexus_info->region.width;
4714 Read meta content from disk.
4716 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4718 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4719 cache_info->cache_filename);
4720 return(MagickFalse);
4722 if ((cache_info->columns == nexus_info->region.width) &&
4723 (extent <= MagickMaxBufferExtent))
4728 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4729 for (y=0; y < (ssize_t) rows; y++)
4731 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4732 cache_info->number_channels*sizeof(Quantum)+offset*
4733 cache_info->metacontent_extent,length,(unsigned char *) q);
4734 if ((MagickSizeType) count != length)
4736 offset+=cache_info->columns;
4737 q+=cache_info->metacontent_extent*nexus_info->region.width;
4739 if (y < (ssize_t) rows)
4741 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4742 cache_info->cache_filename);
4743 return(MagickFalse);
4750 if ((cache_info->debug != MagickFalse) &&
4751 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4752 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4753 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4754 nexus_info->region.width,(double) nexus_info->region.height,(double)
4755 nexus_info->region.x,(double) nexus_info->region.y);
4760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4764 + R e a d P i x e l C a c h e P i x e l s %
4768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4770 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4773 % The format of the ReadPixelCachePixels() method is:
4775 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4776 % NexusInfo *nexus_info,ExceptionInfo *exception)
4778 % A description of each parameter follows:
4780 % o cache_info: the pixel cache.
4782 % o nexus_info: the cache nexus to read the pixels.
4784 % o exception: return any errors or warnings in this structure.
4787 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4788 NexusInfo *nexus_info,ExceptionInfo *exception)
4807 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4809 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4810 nexus_info->region.x;
4811 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4813 rows=nexus_info->region.height;
4815 q=nexus_info->pixels;
4816 switch (cache_info->type)
4825 Read pixels from memory.
4827 if ((cache_info->columns == nexus_info->region.width) &&
4828 (extent == (MagickSizeType) ((size_t) extent)))
4833 p=cache_info->pixels+offset*cache_info->number_channels;
4834 for (y=0; y < (ssize_t) rows; y++)
4836 (void) memcpy(q,p,(size_t) length);
4837 p+=cache_info->number_channels*cache_info->columns;
4838 q+=cache_info->number_channels*nexus_info->region.width;
4845 Read pixels from disk.
4847 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4849 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4850 cache_info->cache_filename);
4851 return(MagickFalse);
4853 if ((cache_info->columns == nexus_info->region.width) &&
4854 (extent <= MagickMaxBufferExtent))
4859 for (y=0; y < (ssize_t) rows; y++)
4861 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4862 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4863 if ((MagickSizeType) count != length)
4865 offset+=cache_info->columns;
4866 q+=cache_info->number_channels*nexus_info->region.width;
4868 if (y < (ssize_t) rows)
4870 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4871 cache_info->cache_filename);
4872 return(MagickFalse);
4879 if ((cache_info->debug != MagickFalse) &&
4880 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4881 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4882 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4883 nexus_info->region.width,(double) nexus_info->region.height,(double)
4884 nexus_info->region.x,(double) nexus_info->region.y);
4889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4893 + R e f e r e n c e P i x e l C a c h e %
4897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4899 % ReferencePixelCache() increments the reference count associated with the
4900 % pixel cache returning a pointer to the cache.
4902 % The format of the ReferencePixelCache method is:
4904 % Cache ReferencePixelCache(Cache cache_info)
4906 % A description of each parameter follows:
4908 % o cache_info: the pixel cache.
4911 MagickPrivate Cache ReferencePixelCache(Cache cache)
4916 assert(cache != (Cache *) NULL);
4917 cache_info=(CacheInfo *) cache;
4918 assert(cache_info->signature == MagickSignature);
4919 LockSemaphoreInfo(cache_info->semaphore);
4920 cache_info->reference_count++;
4921 UnlockSemaphoreInfo(cache_info->semaphore);
4926 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4930 + S e t P i x e l C a c h e M e t h o d s %
4934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4936 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4938 % The format of the SetPixelCacheMethods() method is:
4940 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4942 % A description of each parameter follows:
4944 % o cache: the pixel cache.
4946 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4949 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4954 GetOneAuthenticPixelFromHandler
4955 get_one_authentic_pixel_from_handler;
4957 GetOneVirtualPixelFromHandler
4958 get_one_virtual_pixel_from_handler;
4961 Set cache pixel methods.
4963 assert(cache != (Cache) NULL);
4964 assert(cache_methods != (CacheMethods *) NULL);
4965 cache_info=(CacheInfo *) cache;
4966 assert(cache_info->signature == MagickSignature);
4967 if (cache_info->debug != MagickFalse)
4968 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4969 cache_info->filename);
4970 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4971 cache_info->methods.get_virtual_pixel_handler=
4972 cache_methods->get_virtual_pixel_handler;
4973 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4974 cache_info->methods.destroy_pixel_handler=
4975 cache_methods->destroy_pixel_handler;
4976 if (cache_methods->get_virtual_metacontent_from_handler !=
4977 (GetVirtualMetacontentFromHandler) NULL)
4978 cache_info->methods.get_virtual_metacontent_from_handler=
4979 cache_methods->get_virtual_metacontent_from_handler;
4980 if (cache_methods->get_authentic_pixels_handler !=
4981 (GetAuthenticPixelsHandler) NULL)
4982 cache_info->methods.get_authentic_pixels_handler=
4983 cache_methods->get_authentic_pixels_handler;
4984 if (cache_methods->queue_authentic_pixels_handler !=
4985 (QueueAuthenticPixelsHandler) NULL)
4986 cache_info->methods.queue_authentic_pixels_handler=
4987 cache_methods->queue_authentic_pixels_handler;
4988 if (cache_methods->sync_authentic_pixels_handler !=
4989 (SyncAuthenticPixelsHandler) NULL)
4990 cache_info->methods.sync_authentic_pixels_handler=
4991 cache_methods->sync_authentic_pixels_handler;
4992 if (cache_methods->get_authentic_pixels_from_handler !=
4993 (GetAuthenticPixelsFromHandler) NULL)
4994 cache_info->methods.get_authentic_pixels_from_handler=
4995 cache_methods->get_authentic_pixels_from_handler;
4996 if (cache_methods->get_authentic_metacontent_from_handler !=
4997 (GetAuthenticMetacontentFromHandler) NULL)
4998 cache_info->methods.get_authentic_metacontent_from_handler=
4999 cache_methods->get_authentic_metacontent_from_handler;
5000 get_one_virtual_pixel_from_handler=
5001 cache_info->methods.get_one_virtual_pixel_from_handler;
5002 if (get_one_virtual_pixel_from_handler !=
5003 (GetOneVirtualPixelFromHandler) NULL)
5004 cache_info->methods.get_one_virtual_pixel_from_handler=
5005 cache_methods->get_one_virtual_pixel_from_handler;
5006 get_one_authentic_pixel_from_handler=
5007 cache_methods->get_one_authentic_pixel_from_handler;
5008 if (get_one_authentic_pixel_from_handler !=
5009 (GetOneAuthenticPixelFromHandler) NULL)
5010 cache_info->methods.get_one_authentic_pixel_from_handler=
5011 cache_methods->get_one_authentic_pixel_from_handler;
5015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5019 + S e t P i x e l C a c h e N e x u s P i x e l s %
5023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5025 % SetPixelCacheNexusPixels() defines the region of the cache for the
5026 % specified cache nexus.
5028 % The format of the SetPixelCacheNexusPixels() method is:
5030 % Quantum SetPixelCacheNexusPixels(const Image *image,
5031 % const RectangleInfo *region,NexusInfo *nexus_info,
5032 % ExceptionInfo *exception)
5034 % A description of each parameter follows:
5036 % o image: the image.
5038 % o region: A pointer to the RectangleInfo structure that defines the
5039 % region of this particular cache nexus.
5041 % o nexus_info: the cache nexus to set.
5043 % o exception: return any errors or warnings in this structure.
5047 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5048 NexusInfo *nexus_info,ExceptionInfo *exception)
5050 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5051 return(MagickFalse);
5052 nexus_info->mapped=MagickFalse;
5053 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
5054 nexus_info->length);
5055 if (nexus_info->cache == (Quantum *) NULL)
5057 nexus_info->mapped=MagickTrue;
5058 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
5059 nexus_info->length);
5061 if (nexus_info->cache == (Quantum *) NULL)
5063 (void) ThrowMagickException(exception,GetMagickModule(),
5064 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5065 cache_info->filename);
5066 return(MagickFalse);
5071 static Quantum *SetPixelCacheNexusPixels(const Image *image,
5072 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5084 cache_info=(CacheInfo *) image->cache;
5085 assert(cache_info->signature == MagickSignature);
5086 if (cache_info->type == UndefinedCache)
5087 return((Quantum *) NULL);
5088 nexus_info->region=(*region);
5089 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5090 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5096 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5097 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5098 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5099 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5100 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5101 ((nexus_info->region.width == cache_info->columns) ||
5102 ((nexus_info->region.width % cache_info->columns) == 0)))))
5108 Pixels are accessed directly from memory.
5110 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5111 nexus_info->region.x;
5112 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5114 nexus_info->metacontent=(void *) NULL;
5115 if (cache_info->metacontent_extent != 0)
5116 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5117 offset*cache_info->metacontent_extent;
5118 return(nexus_info->pixels);
5122 Pixels are stored in a cache region until they are synced to the cache.
5124 number_pixels=(MagickSizeType) nexus_info->region.width*
5125 nexus_info->region.height;
5126 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
5127 if (cache_info->metacontent_extent != 0)
5128 length+=number_pixels*cache_info->metacontent_extent;
5129 if (nexus_info->cache == (Quantum *) NULL)
5131 nexus_info->length=length;
5132 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5133 if (status == MagickFalse)
5135 nexus_info->length=0;
5136 return((Quantum *) NULL);
5140 if (nexus_info->length != length)
5142 RelinquishCacheNexusPixels(nexus_info);
5143 nexus_info->length=length;
5144 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5145 if (status == MagickFalse)
5147 nexus_info->length=0;
5148 return((Quantum *) NULL);
5151 nexus_info->pixels=nexus_info->cache;
5152 nexus_info->metacontent=(void *) NULL;
5153 if (cache_info->metacontent_extent != 0)
5154 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
5155 cache_info->number_channels);
5156 return(nexus_info->pixels);
5160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5164 % 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 %
5168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5170 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5171 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5172 % access that is outside the boundaries of the image cache.
5174 % The format of the SetPixelCacheVirtualMethod() method is:
5176 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5177 % const VirtualPixelMethod virtual_pixel_method)
5179 % A description of each parameter follows:
5181 % o image: the image.
5183 % o virtual_pixel_method: choose the type of virtual pixel.
5186 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5187 const VirtualPixelMethod virtual_pixel_method)
5195 assert(image != (Image *) NULL);
5196 assert(image->signature == MagickSignature);
5197 if (image->debug != MagickFalse)
5198 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5199 assert(image->cache != (Cache) NULL);
5200 cache_info=(CacheInfo *) image->cache;
5201 assert(cache_info->signature == MagickSignature);
5202 method=cache_info->virtual_pixel_method;
5203 cache_info->virtual_pixel_method=virtual_pixel_method;
5208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5212 + S y n c A u t h e n t i c P i x e l C a c h e N e x u s %
5216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5218 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5219 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5220 % is synced, otherwise MagickFalse.
5222 % The format of the SyncAuthenticPixelCacheNexus() method is:
5224 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5225 % NexusInfo *nexus_info,ExceptionInfo *exception)
5227 % A description of each parameter follows:
5229 % o image: the image.
5231 % o nexus_info: the cache nexus to sync.
5233 % o exception: return any errors or warnings in this structure.
5236 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5237 NexusInfo *nexus_info,ExceptionInfo *exception)
5246 Transfer pixels to the cache.
5248 assert(image != (Image *) NULL);
5249 assert(image->signature == MagickSignature);
5250 if (image->cache == (Cache) NULL)
5251 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5252 cache_info=(CacheInfo *) image->cache;
5253 assert(cache_info->signature == MagickSignature);
5254 if (cache_info->type == UndefinedCache)
5255 return(MagickFalse);
5256 if ((image->clip_mask != (Image *) NULL) &&
5257 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5258 return(MagickFalse);
5259 if ((image->mask != (Image *) NULL) &&
5260 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5261 return(MagickFalse);
5262 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5264 assert(cache_info->signature == MagickSignature);
5265 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5266 if ((cache_info->metacontent_extent != 0) &&
5267 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5268 return(MagickFalse);
5273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5277 + S y n c A u t h e n t i c P i x e l C a c h e %
5281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5283 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5284 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5285 % otherwise MagickFalse.
5287 % The format of the SyncAuthenticPixelsCache() method is:
5289 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5290 % ExceptionInfo *exception)
5292 % A description of each parameter follows:
5294 % o image: the image.
5296 % o exception: return any errors or warnings in this structure.
5299 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5300 ExceptionInfo *exception)
5306 id = GetOpenMPThreadId();
5311 assert(image != (Image *) NULL);
5312 assert(image->signature == MagickSignature);
5313 assert(image->cache != (Cache) NULL);
5314 cache_info=(CacheInfo *) image->cache;
5315 assert(cache_info->signature == MagickSignature);
5316 assert(id < (int) cache_info->number_threads);
5317 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5327 % S y n c A u t h e n t i c P i x e l s %
5331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5333 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5334 % The method returns MagickTrue if the pixel region is flushed, otherwise
5337 % The format of the SyncAuthenticPixels() method is:
5339 % MagickBooleanType SyncAuthenticPixels(Image *image,
5340 % ExceptionInfo *exception)
5342 % A description of each parameter follows:
5344 % o image: the image.
5346 % o exception: return any errors or warnings in this structure.
5349 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5350 ExceptionInfo *exception)
5356 id = GetOpenMPThreadId();
5361 assert(image != (Image *) NULL);
5362 assert(image->signature == MagickSignature);
5363 assert(image->cache != (Cache) NULL);
5364 cache_info=(CacheInfo *) image->cache;
5365 assert(cache_info->signature == MagickSignature);
5366 if (cache_info->methods.sync_authentic_pixels_handler !=
5367 (SyncAuthenticPixelsHandler) NULL)
5369 status=cache_info->methods.sync_authentic_pixels_handler(image,
5373 assert(id < (int) cache_info->number_threads);
5374 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5384 + S y n c I m a g e P i x e l C a c h e %
5388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5390 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5391 % The method returns MagickTrue if the pixel region is flushed, otherwise
5394 % The format of the SyncImagePixelCache() method is:
5396 % MagickBooleanType SyncImagePixelCache(Image *image,
5397 % ExceptionInfo *exception)
5399 % A description of each parameter follows:
5401 % o image: the image.
5403 % o exception: return any errors or warnings in this structure.
5406 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5407 ExceptionInfo *exception)
5412 assert(image != (Image *) NULL);
5413 assert(exception != (ExceptionInfo *) NULL);
5414 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5415 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5423 + 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 %
5427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5429 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5430 % of the pixel cache.
5432 % The format of the WritePixelCacheMetacontent() method is:
5434 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5435 % NexusInfo *nexus_info,ExceptionInfo *exception)
5437 % A description of each parameter follows:
5439 % o cache_info: the pixel cache.
5441 % o nexus_info: the cache nexus to write the meta-content.
5443 % o exception: return any errors or warnings in this structure.
5446 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5447 NexusInfo *nexus_info,ExceptionInfo *exception)
5457 register const unsigned char
5466 if (cache_info->metacontent_extent == 0)
5467 return(MagickFalse);
5468 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5470 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5471 nexus_info->region.x;
5472 length=(MagickSizeType) nexus_info->region.width*
5473 cache_info->metacontent_extent;
5474 rows=nexus_info->region.height;
5475 extent=(MagickSizeType) length*rows;
5476 p=(unsigned char *) nexus_info->metacontent;
5477 switch (cache_info->type)
5482 register unsigned char
5486 Write associated pixels to memory.
5488 if ((cache_info->columns == nexus_info->region.width) &&
5489 (extent == (MagickSizeType) ((size_t) extent)))
5494 q=(unsigned char *) cache_info->metacontent+offset*
5495 cache_info->metacontent_extent;
5496 for (y=0; y < (ssize_t) rows; y++)
5498 (void) memcpy(q,p,(size_t) length);
5499 p+=nexus_info->region.width*cache_info->metacontent_extent;
5500 q+=cache_info->columns*cache_info->metacontent_extent;
5507 Write associated pixels to disk.
5509 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5511 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5512 cache_info->cache_filename);
5513 return(MagickFalse);
5515 if ((cache_info->columns == nexus_info->region.width) &&
5516 (extent <= MagickMaxBufferExtent))
5521 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5522 for (y=0; y < (ssize_t) rows; y++)
5524 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5525 cache_info->number_channels*sizeof(Quantum)+offset*
5526 cache_info->metacontent_extent,length,(const unsigned char *) p);
5527 if ((MagickSizeType) count != length)
5529 p+=nexus_info->region.width*cache_info->metacontent_extent;
5530 offset+=cache_info->columns;
5532 if (y < (ssize_t) rows)
5534 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5535 cache_info->cache_filename);
5536 return(MagickFalse);
5543 if ((cache_info->debug != MagickFalse) &&
5544 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5545 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5546 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5547 nexus_info->region.width,(double) nexus_info->region.height,(double)
5548 nexus_info->region.x,(double) nexus_info->region.y);
5553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5557 + W r i t e C a c h e P i x e l s %
5561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5563 % WritePixelCachePixels() writes image pixels to the specified region of the
5566 % The format of the WritePixelCachePixels() method is:
5568 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5569 % NexusInfo *nexus_info,ExceptionInfo *exception)
5571 % A description of each parameter follows:
5573 % o cache_info: the pixel cache.
5575 % o nexus_info: the cache nexus to write the pixels.
5577 % o exception: return any errors or warnings in this structure.
5580 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5581 NexusInfo *nexus_info,ExceptionInfo *exception)
5591 register const Quantum
5600 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5602 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5603 nexus_info->region.x;
5604 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5606 rows=nexus_info->region.height;
5608 p=nexus_info->pixels;
5609 switch (cache_info->type)
5618 Write pixels to memory.
5620 if ((cache_info->columns == nexus_info->region.width) &&
5621 (extent == (MagickSizeType) ((size_t) extent)))
5626 q=cache_info->pixels+offset*cache_info->number_channels;
5627 for (y=0; y < (ssize_t) rows; y++)
5629 (void) memcpy(q,p,(size_t) length);
5630 p+=nexus_info->region.width*cache_info->number_channels;
5631 q+=cache_info->columns*cache_info->number_channels;
5638 Write pixels to disk.
5640 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5642 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5643 cache_info->cache_filename);
5644 return(MagickFalse);
5646 if ((cache_info->columns == nexus_info->region.width) &&
5647 (extent <= MagickMaxBufferExtent))
5652 for (y=0; y < (ssize_t) rows; y++)
5654 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5655 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5657 if ((MagickSizeType) count != length)
5659 p+=nexus_info->region.width*cache_info->number_channels;
5660 offset+=cache_info->columns;
5662 if (y < (ssize_t) rows)
5664 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5665 cache_info->cache_filename);
5666 return(MagickFalse);
5673 if ((cache_info->debug != MagickFalse) &&
5674 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5675 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5676 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5677 nexus_info->region.width,(double) nexus_info->region.height,(double)
5678 nexus_info->region.x,(double) nexus_info->region.y);