2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/cache-private.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/composite-private.h"
50 #include "MagickCore/exception.h"
51 #include "MagickCore/exception-private.h"
52 #include "MagickCore/geometry.h"
53 #include "MagickCore/list.h"
54 #include "MagickCore/log.h"
55 #include "MagickCore/magick.h"
56 #include "MagickCore/memory_.h"
57 #include "MagickCore/pixel.h"
58 #include "MagickCore/pixel-accessor.h"
59 #include "MagickCore/policy.h"
60 #include "MagickCore/quantum.h"
61 #include "MagickCore/random_.h"
62 #include "MagickCore/resource_.h"
63 #include "MagickCore/semaphore.h"
64 #include "MagickCore/splay-tree.h"
65 #include "MagickCore/string_.h"
66 #include "MagickCore/string-private.h"
67 #include "MagickCore/thread-private.h"
68 #include "MagickCore/utility.h"
69 #include "MagickCore/utility-private.h"
70 #if defined(MAGICKCORE_ZLIB_DELEGATE)
77 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
82 typedef struct _MagickModulo
112 Forward declarations.
114 #if defined(__cplusplus) || defined(c_plusplus)
119 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
120 const ssize_t,const size_t,const size_t,ExceptionInfo *),
121 *GetVirtualPixelsCache(const Image *);
124 *GetVirtualMetacontentFromCache(const Image *);
126 static MagickBooleanType
127 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
128 Quantum *,ExceptionInfo *),
129 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
130 const ssize_t,const ssize_t,Quantum *,ExceptionInfo *),
131 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
132 ReadPixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
134 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
135 WritePixelCacheMetacontent(CacheInfo *,NexusInfo *,ExceptionInfo *),
136 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
139 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
140 const size_t,ExceptionInfo *),
141 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
142 const size_t,ExceptionInfo *),
143 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
146 #if defined(__cplusplus) || defined(c_plusplus)
153 static volatile MagickBooleanType
154 instantiate_cache = MagickFalse;
157 *cache_semaphore = (SemaphoreInfo *) NULL;
160 *cache_resources = (SplayTreeInfo *) NULL;
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167 + A c q u i r e P i x e l C a c h e %
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173 % AcquirePixelCache() acquires a pixel cache.
175 % The format of the AcquirePixelCache() method is:
177 % Cache AcquirePixelCache(const size_t number_threads)
179 % A description of each parameter follows:
181 % o number_threads: the number of nexus threads.
184 MagickPrivate Cache AcquirePixelCache(const size_t number_threads)
189 cache_info=(CacheInfo *) AcquireQuantumMemory(1,sizeof(*cache_info));
190 if (cache_info == (CacheInfo *) NULL)
191 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
192 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
193 cache_info->type=UndefinedCache;
194 cache_info->mode=IOMode;
195 cache_info->colorspace=RGBColorspace;
196 cache_info->file=(-1);
197 cache_info->id=GetMagickThreadId();
198 cache_info->number_threads=number_threads;
199 if (number_threads == 0)
200 cache_info->number_threads=GetOpenMPMaximumThreads();
201 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
202 if (cache_info->nexus_info == (NexusInfo **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
204 cache_info->semaphore=AllocateSemaphoreInfo();
205 cache_info->reference_count=1;
206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
214 LockSemaphoreInfo(cache_semaphore);
215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
222 UnlockSemaphoreInfo(cache_semaphore);
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 % A c q u i r e P i x e l C a c h e N e x u s %
237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
241 % The format of the AcquirePixelCacheNexus method is:
243 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
245 % A description of each parameter follows:
247 % o number_threads: the number of nexus threads.
250 MagickPrivate NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
258 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
259 sizeof(*nexus_info));
260 if (nexus_info == (NexusInfo **) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
262 for (i=0; i < (ssize_t) number_threads; i++)
264 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
265 if (nexus_info[i] == (NexusInfo *) NULL)
266 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
267 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
268 nexus_info[i]->signature=MagickSignature;
274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
278 + A c q u i r e P i x e l C a c h e P i x e l s %
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284 % AcquirePixelCachePixels() returns the pixels associated with the specified
287 % The format of the AcquirePixelCachePixels() method is:
289 % const void *AcquirePixelCachePixels(const Image *image,
290 % MagickSizeType *length,ExceptionInfo *exception)
292 % A description of each parameter follows:
294 % o image: the image.
296 % o length: the pixel cache length.
298 % o exception: return any errors or warnings in this structure.
301 MagickPrivate const void *AcquirePixelCachePixels(const Image *image,
302 MagickSizeType *length,ExceptionInfo *exception)
307 assert(image != (const Image *) NULL);
308 assert(image->signature == MagickSignature);
309 assert(exception != (ExceptionInfo *) NULL);
310 assert(exception->signature == MagickSignature);
311 assert(image->cache != (Cache) NULL);
312 cache_info=(CacheInfo *) image->cache;
313 assert(cache_info->signature == MagickSignature);
315 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
316 return((const void *) NULL);
317 *length=cache_info->length;
318 return((const void *) cache_info->pixels);
322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326 + C a c h e C o m p o n e n t G e n e s i s %
330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332 % CacheComponentGenesis() instantiates the cache component.
334 % The format of the CacheComponentGenesis method is:
336 % MagickBooleanType CacheComponentGenesis(void)
339 MagickPrivate MagickBooleanType CacheComponentGenesis(void)
341 AcquireSemaphoreInfo(&cache_semaphore);
346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 + C a c h e C o m p o n e n t T e r m i n u s %
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356 % CacheComponentTerminus() destroys the cache component.
358 % The format of the CacheComponentTerminus() method is:
360 % CacheComponentTerminus(void)
363 MagickPrivate void CacheComponentTerminus(void)
365 if (cache_semaphore == (SemaphoreInfo *) NULL)
366 AcquireSemaphoreInfo(&cache_semaphore);
367 LockSemaphoreInfo(cache_semaphore);
368 if (cache_resources != (SplayTreeInfo *) NULL)
369 cache_resources=DestroySplayTree(cache_resources);
370 instantiate_cache=MagickFalse;
371 UnlockSemaphoreInfo(cache_semaphore);
372 DestroySemaphoreInfo(&cache_semaphore);
376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380 + C l i p P i x e l C a c h e N e x u s %
384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386 % ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
387 % mask. It returns MagickTrue if the pixel region is clipped, otherwise
390 % The format of the ClipPixelCacheNexus() method is:
392 % MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
393 % ExceptionInfo *exception)
395 % A description of each parameter follows:
397 % o image: the image.
399 % o nexus_info: the cache nexus to clip.
401 % o exception: return any errors or warnings in this structure.
404 static MagickBooleanType ClipPixelCacheNexus(Image *image,
405 NexusInfo *nexus_info,ExceptionInfo *exception)
417 register const Quantum
430 if (image->debug != MagickFalse)
431 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
432 if (image->clip_mask == (Image *) NULL)
434 cache_info=(CacheInfo *) image->cache;
435 if (cache_info == (Cache) NULL)
437 image_nexus=AcquirePixelCacheNexus(1);
438 clip_nexus=AcquirePixelCacheNexus(1);
439 if ((image_nexus == (NexusInfo **) NULL) ||
440 (clip_nexus == (NexusInfo **) NULL))
441 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
442 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
443 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
444 nexus_info->region.height,image_nexus[0],exception);
445 q=nexus_info->pixels;
446 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
447 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
448 nexus_info->region.height,clip_nexus[0],exception);
449 number_pixels=(MagickSizeType) nexus_info->region.width*
450 nexus_info->region.height;
451 for (i=0; i < (ssize_t) number_pixels; i++)
453 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
455 if (GetPixelIntensity(image,r) > ((Quantum) QuantumRange/2))
457 SetPixelRed(image,GetPixelRed(image,p),q);
458 SetPixelGreen(image,GetPixelGreen(image,p),q);
459 SetPixelBlue(image,GetPixelBlue(image,p),q);
460 if (cache_info->colorspace == CMYKColorspace)
461 SetPixelBlack(image,GetPixelBlack(image,p),q);
462 SetPixelAlpha(image,GetPixelAlpha(image,p),q);
464 p+=GetPixelChannels(image);
465 q+=GetPixelChannels(image);
466 r+=GetPixelChannels(image->clip_mask);
468 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
469 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
470 if (i < (ssize_t) number_pixels)
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
480 + C l o n e P i x e l C a c h e %
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486 % ClonePixelCache() clones a pixel cache.
488 % The format of the ClonePixelCache() method is:
490 % Cache ClonePixelCache(const Cache cache)
492 % A description of each parameter follows:
494 % o cache: the pixel cache.
497 MagickPrivate Cache ClonePixelCache(const Cache cache)
505 assert(cache != NULL);
506 cache_info=(const CacheInfo *) cache;
507 assert(cache_info->signature == MagickSignature);
508 if (cache_info->debug != MagickFalse)
509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
510 cache_info->filename);
511 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
512 if (clone_info == (Cache) NULL)
513 return((Cache) NULL);
514 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
515 return((Cache ) clone_info);
519 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
523 + C l o n e P i x e l C a c h e P i x e l s %
527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
528 % ClonePixelCachePixels() clones the source pixel cache to the destination
531 % The format of the ClonePixelCachePixels() method is:
533 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
534 % CacheInfo *source_info,ExceptionInfo *exception)
536 % A description of each parameter follows:
538 % o cache_info: the pixel cache.
540 % o source_info: the source pixel cache.
542 % o exception: return any errors or warnings in this structure.
546 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
552 LockSemaphoreInfo(cache_info->disk_semaphore);
553 if (cache_info->file != -1)
555 status=close(cache_info->file);
556 cache_info->file=(-1);
557 RelinquishMagickResource(FileResource,1);
559 UnlockSemaphoreInfo(cache_info->disk_semaphore);
560 return(status == -1 ? MagickFalse : MagickTrue);
563 static void LimitPixelCacheDescriptors(void)
570 Limit # of open file descriptors.
572 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
574 LockSemaphoreInfo(cache_semaphore);
575 if (cache_resources == (SplayTreeInfo *) NULL)
577 UnlockSemaphoreInfo(cache_semaphore);
580 ResetSplayTreeIterator(cache_resources);
581 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
582 while (p != (CacheInfo *) NULL)
584 if ((p->type == DiskCache) && (p->file != -1))
586 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
588 for (q=p; p != (CacheInfo *) NULL; )
590 if ((p->type == DiskCache) && (p->file != -1) &&
591 (p->timestamp < q->timestamp))
593 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
595 if (q != (CacheInfo *) NULL)
598 Close least recently used cache.
600 (void) close(q->file);
603 UnlockSemaphoreInfo(cache_semaphore);
606 static inline MagickSizeType MagickMax(const MagickSizeType x,
607 const MagickSizeType y)
614 static inline MagickSizeType MagickMin(const MagickSizeType x,
615 const MagickSizeType y)
622 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
629 Open pixel cache on disk.
631 LockSemaphoreInfo(cache_info->disk_semaphore);
632 if (cache_info->file != -1)
634 UnlockSemaphoreInfo(cache_info->disk_semaphore);
635 return(MagickTrue); /* cache already open */
637 LimitPixelCacheDescriptors();
638 if (*cache_info->cache_filename == '\0')
639 file=AcquireUniqueFileResource(cache_info->cache_filename);
645 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
650 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
651 O_BINARY | O_EXCL,S_MODE);
653 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
659 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
662 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
668 UnlockSemaphoreInfo(cache_info->disk_semaphore);
671 (void) AcquireMagickResource(FileResource,1);
672 cache_info->file=file;
673 cache_info->mode=mode;
674 cache_info->timestamp=time(0);
675 UnlockSemaphoreInfo(cache_info->disk_semaphore);
679 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
680 const MagickOffsetType offset,const MagickSizeType length,
681 unsigned char *restrict buffer)
683 register MagickOffsetType
689 cache_info->timestamp=time(0);
690 #if !defined(MAGICKCORE_HAVE_PREAD)
691 LockSemaphoreInfo(cache_info->disk_semaphore);
692 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
694 UnlockSemaphoreInfo(cache_info->disk_semaphore);
695 return((MagickOffsetType) -1);
699 for (i=0; i < (MagickOffsetType) length; i+=count)
701 #if !defined(MAGICKCORE_HAVE_PREAD)
702 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
703 (MagickSizeType) SSIZE_MAX));
705 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
706 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
717 #if !defined(MAGICKCORE_HAVE_PREAD)
718 UnlockSemaphoreInfo(cache_info->disk_semaphore);
723 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
724 const MagickOffsetType offset,const MagickSizeType length,
725 const unsigned char *restrict buffer)
727 register MagickOffsetType
733 cache_info->timestamp=time(0);
734 #if !defined(MAGICKCORE_HAVE_PWRITE)
735 LockSemaphoreInfo(cache_info->disk_semaphore);
736 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
738 UnlockSemaphoreInfo(cache_info->disk_semaphore);
739 return((MagickOffsetType) -1);
743 for (i=0; i < (MagickOffsetType) length; i+=count)
745 #if !defined(MAGICKCORE_HAVE_PWRITE)
746 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
747 (MagickSizeType) SSIZE_MAX));
749 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
750 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
761 #if !defined(MAGICKCORE_HAVE_PWRITE)
762 UnlockSemaphoreInfo(cache_info->disk_semaphore);
767 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
768 CacheInfo *cache_info,ExceptionInfo *exception)
773 register MagickOffsetType
783 Clone pixel cache (both caches on disk).
785 if (cache_info->debug != MagickFalse)
786 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
787 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
789 if (blob == (unsigned char *) NULL)
791 (void) ThrowMagickException(exception,GetMagickModule(),
792 ResourceLimitError,"MemoryAllocationFailed","`%s'",
793 cache_info->filename);
796 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
798 blob=(unsigned char *) RelinquishMagickMemory(blob);
799 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
800 cache_info->cache_filename);
803 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
805 (void) ClosePixelCacheOnDisk(cache_info);
806 blob=(unsigned char *) RelinquishMagickMemory(blob);
807 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
808 clone_info->cache_filename);
812 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
814 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
815 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
819 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
820 cache_info->cache_filename);
823 length=(size_t) count;
824 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
825 if ((MagickSizeType) count != length)
827 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
828 clone_info->cache_filename);
832 (void) ClosePixelCacheOnDisk(clone_info);
833 (void) ClosePixelCacheOnDisk(cache_info);
834 blob=(unsigned char *) RelinquishMagickMemory(blob);
835 if (i < (MagickOffsetType) cache_info->length)
840 static MagickBooleanType OptimizedPixelCacheClone(CacheInfo *clone_info,
841 CacheInfo *cache_info,ExceptionInfo *exception)
846 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
849 Clone pixel cache (both caches in memory).
851 if (cache_info->debug != MagickFalse)
852 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
853 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
857 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
860 Clone pixel cache (one cache on disk, one in memory).
862 if (cache_info->debug != MagickFalse)
863 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
864 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
866 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
867 cache_info->cache_filename);
870 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
871 cache_info->length,(unsigned char *) clone_info->pixels);
872 (void) ClosePixelCacheOnDisk(cache_info);
873 if ((MagickSizeType) count != cache_info->length)
875 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
876 cache_info->cache_filename);
881 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
884 Clone pixel cache (one cache on disk, one in memory).
886 if (clone_info->debug != MagickFalse)
887 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
888 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
890 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
891 clone_info->cache_filename);
894 count=WritePixelCacheRegion(clone_info,clone_info->offset,
895 clone_info->length,(unsigned char *) cache_info->pixels);
896 (void) ClosePixelCacheOnDisk(clone_info);
897 if ((MagickSizeType) count != clone_info->length)
899 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
900 clone_info->cache_filename);
906 Clone pixel cache (both caches on disk).
908 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
911 static MagickBooleanType UnoptimizedPixelCacheClone(CacheInfo *clone_info,
912 CacheInfo *cache_info,ExceptionInfo *exception)
935 Clone pixel cache (unoptimized).
937 if (cache_info->debug != MagickFalse)
939 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
940 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
942 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
943 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
945 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
946 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
948 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
950 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
951 clone_info->number_channels)*sizeof(Quantum),MagickMax(
952 cache_info->metacontent_extent,clone_info->metacontent_extent));
953 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
954 if (blob == (unsigned char *) NULL)
956 (void) ThrowMagickException(exception,GetMagickModule(),
957 ResourceLimitError,"MemoryAllocationFailed","`%s'",
958 cache_info->filename);
961 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
964 if (cache_info->type == DiskCache)
966 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
968 blob=(unsigned char *) RelinquishMagickMemory(blob);
969 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
970 cache_info->cache_filename);
973 cache_offset=cache_info->offset;
975 if (clone_info->type == DiskCache)
977 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
979 blob=(unsigned char *) RelinquishMagickMemory(blob);
980 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
981 clone_info->cache_filename);
984 clone_offset=clone_info->offset;
987 Clone pixel channels.
990 for (y=0; y < (ssize_t) cache_info->rows; y++)
992 for (x=0; x < (ssize_t) cache_info->columns; x++)
998 Read a set of pixel channels.
1000 length=cache_info->number_channels*sizeof(Quantum);
1001 if (cache_info->type != DiskCache)
1002 (void) memcpy(blob,(unsigned char *) cache_info->pixels+cache_offset,
1006 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1007 if ((MagickSizeType) count != length)
1013 cache_offset+=length;
1014 if ((y < (ssize_t) clone_info->rows) &&
1015 (x < (ssize_t) clone_info->columns))
1016 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
1028 Write a set of pixel channels.
1030 channel=clone_info->channel_map[i].channel;
1031 traits=cache_info->channel_map[channel].traits;
1032 if (traits == UndefinedPixelTrait)
1034 clone_offset+=sizeof(Quantum);
1037 offset=cache_info->channel_map[channel].offset;
1038 if (clone_info->type != DiskCache)
1039 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1040 blob+offset*sizeof(Quantum),sizeof(Quantum));
1043 count=WritePixelCacheRegion(clone_info,clone_offset,
1044 sizeof(Quantum),blob+offset*sizeof(Quantum));
1045 if ((MagickSizeType) count != sizeof(Quantum))
1051 clone_offset+=sizeof(Quantum);
1054 length=clone_info->number_channels*sizeof(Quantum);
1055 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1056 for ( ; x < (ssize_t) clone_info->columns; x++)
1059 Set remaining columns as undefined.
1061 if (clone_info->type != DiskCache)
1062 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1066 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1067 if ((MagickSizeType) count != length)
1073 clone_offset+=length;
1076 length=clone_info->number_channels*sizeof(Quantum);
1077 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1078 for ( ; y < (ssize_t) clone_info->rows; y++)
1081 Set remaining rows as undefined.
1083 for (x=0; x < (ssize_t) clone_info->columns; x++)
1085 if (clone_info->type != DiskCache)
1086 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1090 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1091 if ((MagickSizeType) count != length)
1097 clone_offset+=length;
1100 if ((cache_info->metacontent_extent != 0) ||
1101 (clone_info->metacontent_extent != 0))
1106 for (y=0; y < (ssize_t) cache_info->rows; y++)
1108 for (x=0; x < (ssize_t) cache_info->columns; x++)
1111 Read a set of metacontent.
1113 length=cache_info->metacontent_extent;
1114 if (cache_info->type != DiskCache)
1115 (void) memcpy(blob,(unsigned char *) cache_info->pixels+
1116 cache_offset,length);
1119 count=ReadPixelCacheRegion(cache_info,cache_offset,length,blob);
1120 if ((MagickSizeType) count != length)
1126 cache_offset+=length;
1127 if ((y < (ssize_t) clone_info->rows) &&
1128 (x < (ssize_t) clone_info->columns))
1131 Write a set of metacontent.
1133 length=clone_info->metacontent_extent;
1134 if (clone_info->type != DiskCache)
1135 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1139 count=WritePixelCacheRegion(clone_info,clone_offset,length,
1141 if ((MagickSizeType) count != length)
1147 clone_offset+=length;
1150 length=clone_info->metacontent_extent;
1151 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1152 for ( ; x < (ssize_t) clone_info->columns; x++)
1155 Set remaining columns as undefined.
1157 if (clone_info->type != DiskCache)
1158 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1162 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
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 ( ; y < (ssize_t) clone_info->rows; y++)
1177 Set remaining rows as undefined.
1179 for (x=0; x < (ssize_t) clone_info->columns; x++)
1181 if (clone_info->type != DiskCache)
1182 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1186 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1187 if ((MagickSizeType) count != length)
1193 clone_offset+=length;
1197 if (clone_info->type == DiskCache)
1198 (void) ClosePixelCacheOnDisk(clone_info);
1199 if (cache_info->type == DiskCache)
1200 (void) ClosePixelCacheOnDisk(cache_info);
1201 blob=(unsigned char *) RelinquishMagickMemory(blob);
1205 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1206 CacheInfo *cache_info,ExceptionInfo *exception)
1212 if (cache_info->type == PingCache)
1214 p=cache_info->channel_map;
1215 q=clone_info->channel_map;
1216 if ((cache_info->columns == clone_info->columns) &&
1217 (cache_info->rows == clone_info->rows) &&
1218 (cache_info->number_channels == clone_info->number_channels) &&
1219 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1220 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1221 return(OptimizedPixelCacheClone(clone_info,cache_info,exception));
1222 return(UnoptimizedPixelCacheClone(clone_info,cache_info,exception));
1226 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1230 + C l o n e P i x e l C a c h e M e t h o d s %
1234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1236 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1239 % The format of the ClonePixelCacheMethods() method is:
1241 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1243 % A description of each parameter follows:
1245 % o clone: Specifies a pointer to a Cache structure.
1247 % o cache: the pixel cache.
1250 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1256 assert(clone != (Cache) NULL);
1257 source_info=(CacheInfo *) clone;
1258 assert(source_info->signature == MagickSignature);
1259 if (source_info->debug != MagickFalse)
1260 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1261 source_info->filename);
1262 assert(cache != (Cache) NULL);
1263 cache_info=(CacheInfo *) cache;
1264 assert(cache_info->signature == MagickSignature);
1265 source_info->methods=cache_info->methods;
1269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1273 + D e s t r o y I m a g e P i x e l C a c h e %
1277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1279 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1281 % The format of the DestroyImagePixelCache() method is:
1283 % void DestroyImagePixelCache(Image *image)
1285 % A description of each parameter follows:
1287 % o image: the image.
1290 static void DestroyImagePixelCache(Image *image)
1292 assert(image != (Image *) NULL);
1293 assert(image->signature == MagickSignature);
1294 if (image->debug != MagickFalse)
1295 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1296 if (image->cache == (void *) NULL)
1298 image->cache=DestroyPixelCache(image->cache);
1302 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1306 + D e s t r o y I m a g e P i x e l s %
1310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1314 % The format of the DestroyImagePixels() method is:
1316 % void DestroyImagePixels(Image *image)
1318 % A description of each parameter follows:
1320 % o image: the image.
1323 MagickExport void DestroyImagePixels(Image *image)
1328 assert(image != (const Image *) NULL);
1329 assert(image->signature == MagickSignature);
1330 if (image->debug != MagickFalse)
1331 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1332 assert(image->cache != (Cache) NULL);
1333 cache_info=(CacheInfo *) image->cache;
1334 assert(cache_info->signature == MagickSignature);
1335 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1337 cache_info->methods.destroy_pixel_handler(image);
1340 image->cache=DestroyPixelCache(image->cache);
1344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1348 + D e s t r o y P i x e l C a c h e %
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1356 % The format of the DestroyPixelCache() method is:
1358 % Cache DestroyPixelCache(Cache cache)
1360 % A description of each parameter follows:
1362 % o cache: the pixel cache.
1366 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1368 switch (cache_info->type)
1372 if (cache_info->mapped == MagickFalse)
1373 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
1374 cache_info->pixels);
1376 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1377 (size_t) cache_info->length);
1378 RelinquishMagickResource(MemoryResource,cache_info->length);
1383 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1384 cache_info->length);
1385 RelinquishMagickResource(MapResource,cache_info->length);
1389 if (cache_info->file != -1)
1390 (void) ClosePixelCacheOnDisk(cache_info);
1391 RelinquishMagickResource(DiskResource,cache_info->length);
1397 cache_info->type=UndefinedCache;
1398 cache_info->mapped=MagickFalse;
1399 cache_info->metacontent=(void *) NULL;
1402 MagickPrivate Cache DestroyPixelCache(Cache cache)
1407 assert(cache != (Cache) NULL);
1408 cache_info=(CacheInfo *) cache;
1409 assert(cache_info->signature == MagickSignature);
1410 if (cache_info->debug != MagickFalse)
1411 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1412 cache_info->filename);
1413 LockSemaphoreInfo(cache_info->semaphore);
1414 cache_info->reference_count--;
1415 if (cache_info->reference_count != 0)
1417 UnlockSemaphoreInfo(cache_info->semaphore);
1418 return((Cache) NULL);
1420 UnlockSemaphoreInfo(cache_info->semaphore);
1421 if (cache_resources != (SplayTreeInfo *) NULL)
1422 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1423 if (cache_info->debug != MagickFalse)
1426 message[MaxTextExtent];
1428 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1429 cache_info->filename);
1430 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1432 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1433 (cache_info->type != DiskCache)))
1434 RelinquishPixelCachePixels(cache_info);
1437 RelinquishPixelCachePixels(cache_info);
1438 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1440 *cache_info->cache_filename='\0';
1441 if (cache_info->nexus_info != (NexusInfo **) NULL)
1442 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1443 cache_info->number_threads);
1444 if (cache_info->random_info != (RandomInfo *) NULL)
1445 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1446 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1447 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1448 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1449 DestroySemaphoreInfo(&cache_info->semaphore);
1450 cache_info->signature=(~MagickSignature);
1451 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1461 + D e s t r o y P i x e l C a c h e N e x u s %
1465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1469 % The format of the DestroyPixelCacheNexus() method is:
1471 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1472 % const size_t number_threads)
1474 % A description of each parameter follows:
1476 % o nexus_info: the nexus to destroy.
1478 % o number_threads: the number of nexus threads.
1482 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1484 if (nexus_info->mapped == MagickFalse)
1485 (void) RelinquishMagickMemory(nexus_info->cache);
1487 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1488 nexus_info->cache=(Quantum *) NULL;
1489 nexus_info->pixels=(Quantum *) NULL;
1490 nexus_info->metacontent=(void *) NULL;
1491 nexus_info->length=0;
1492 nexus_info->mapped=MagickFalse;
1495 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1496 const size_t number_threads)
1501 assert(nexus_info != (NexusInfo **) NULL);
1502 for (i=0; i < (ssize_t) number_threads; i++)
1504 if (nexus_info[i]->cache != (Quantum *) NULL)
1505 RelinquishCacheNexusPixels(nexus_info[i]);
1506 nexus_info[i]->signature=(~MagickSignature);
1507 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1509 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1518 % G e t A u t h e n t i c M e t a c o n t e n t %
1522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1524 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1525 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1526 % returned if the associated pixels are not available.
1528 % The format of the GetAuthenticMetacontent() method is:
1530 % void *GetAuthenticMetacontent(const Image *image)
1532 % A description of each parameter follows:
1534 % o image: the image.
1537 MagickExport void *GetAuthenticMetacontent(const Image *image)
1543 id = GetOpenMPThreadId();
1548 assert(image != (const Image *) NULL);
1549 assert(image->signature == MagickSignature);
1550 assert(image->cache != (Cache) NULL);
1551 cache_info=(CacheInfo *) image->cache;
1552 assert(cache_info->signature == MagickSignature);
1553 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1554 (GetAuthenticMetacontentFromHandler) NULL)
1556 metacontent=cache_info->methods.
1557 get_authentic_metacontent_from_handler(image);
1558 return(metacontent);
1560 assert(id < (int) cache_info->number_threads);
1561 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1562 cache_info->nexus_info[id]);
1563 return(metacontent);
1567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1571 + 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 %
1575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1577 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1578 % with the last call to QueueAuthenticPixelsCache() or
1579 % GetAuthenticPixelsCache().
1581 % The format of the GetAuthenticMetacontentFromCache() method is:
1583 % void *GetAuthenticMetacontentFromCache(const Image *image)
1585 % A description of each parameter follows:
1587 % o image: the image.
1590 static void *GetAuthenticMetacontentFromCache(const Image *image)
1596 id = GetOpenMPThreadId();
1601 assert(image != (const Image *) NULL);
1602 assert(image->signature == MagickSignature);
1603 assert(image->cache != (Cache) NULL);
1604 cache_info=(CacheInfo *) image->cache;
1605 assert(cache_info->signature == MagickSignature);
1606 assert(id < (int) cache_info->number_threads);
1607 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1608 cache_info->nexus_info[id]);
1609 return(metacontent);
1613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1617 + 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 %
1621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1624 % disk pixel cache as defined by the geometry parameters. A pointer to the
1625 % pixels is returned if the pixels are transferred, otherwise a NULL is
1628 % The format of the GetAuthenticPixelCacheNexus() method is:
1630 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1631 % const ssize_t y,const size_t columns,const size_t rows,
1632 % NexusInfo *nexus_info,ExceptionInfo *exception)
1634 % A description of each parameter follows:
1636 % o image: the image.
1638 % o x,y,columns,rows: These values define the perimeter of a region of
1641 % o nexus_info: the cache nexus to return.
1643 % o exception: return any errors or warnings in this structure.
1647 static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
1648 NexusInfo *nexus_info)
1656 if (cache_info->type == PingCache)
1658 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1659 nexus_info->region.x;
1660 status=nexus_info->pixels == (cache_info->pixels+offset*
1661 cache_info->number_channels) ? MagickTrue : MagickFalse;
1665 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1666 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1667 NexusInfo *nexus_info,ExceptionInfo *exception)
1676 Transfer pixels from the cache.
1678 assert(image != (Image *) NULL);
1679 assert(image->signature == MagickSignature);
1680 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
1681 if (q == (Quantum *) NULL)
1682 return((Quantum *) NULL);
1683 cache_info=(CacheInfo *) image->cache;
1684 assert(cache_info->signature == MagickSignature);
1685 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1687 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1688 return((Quantum *) NULL);
1689 if (cache_info->metacontent_extent != 0)
1690 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1691 return((Quantum *) NULL);
1696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1700 + 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 %
1704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1706 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1707 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1709 % The format of the GetAuthenticPixelsFromCache() method is:
1711 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1713 % A description of each parameter follows:
1715 % o image: the image.
1718 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1724 id = GetOpenMPThreadId();
1726 assert(image != (const Image *) NULL);
1727 assert(image->signature == MagickSignature);
1728 assert(image->cache != (Cache) NULL);
1729 cache_info=(CacheInfo *) image->cache;
1730 assert(cache_info->signature == MagickSignature);
1731 assert(id < (int) cache_info->number_threads);
1732 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1740 % G e t A u t h e n t i c P i x e l Q u e u e %
1744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1746 % GetAuthenticPixelQueue() returns the authentic pixels associated
1747 % corresponding with the last call to QueueAuthenticPixels() or
1748 % GetAuthenticPixels().
1750 % The format of the GetAuthenticPixelQueue() method is:
1752 % Quantum *GetAuthenticPixelQueue(const Image image)
1754 % A description of each parameter follows:
1756 % o image: the image.
1759 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1765 id = GetOpenMPThreadId();
1767 assert(image != (const Image *) NULL);
1768 assert(image->signature == MagickSignature);
1769 assert(image->cache != (Cache) NULL);
1770 cache_info=(CacheInfo *) image->cache;
1771 assert(cache_info->signature == MagickSignature);
1772 if (cache_info->methods.get_authentic_pixels_from_handler !=
1773 (GetAuthenticPixelsFromHandler) NULL)
1774 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1775 assert(id < (int) cache_info->number_threads);
1776 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1784 % G e t A u t h e n t i c P i x e l s %
1787 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1789 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1790 % region is successfully accessed, a pointer to a Quantum array
1791 % representing the region is returned, otherwise NULL is returned.
1793 % The returned pointer may point to a temporary working copy of the pixels
1794 % or it may point to the original pixels in memory. Performance is maximized
1795 % if the selected region is part of one row, or one or more full rows, since
1796 % then there is opportunity to access the pixels in-place (without a copy)
1797 % if the image is in memory, or in a memory-mapped file. The returned pointer
1798 % must *never* be deallocated by the user.
1800 % Pixels accessed via the returned pointer represent a simple array of type
1801 % Quantum. If the image has corresponding metacontent,call
1802 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1803 % meta-content corresponding to the region. Once the Quantum array has
1804 % been updated, the changes must be saved back to the underlying image using
1805 % SyncAuthenticPixels() or they may be lost.
1807 % The format of the GetAuthenticPixels() method is:
1809 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1810 % const ssize_t y,const size_t columns,const size_t rows,
1811 % ExceptionInfo *exception)
1813 % A description of each parameter follows:
1815 % o image: the image.
1817 % o x,y,columns,rows: These values define the perimeter of a region of
1820 % o exception: return any errors or warnings in this structure.
1823 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1824 const ssize_t y,const size_t columns,const size_t rows,
1825 ExceptionInfo *exception)
1831 id = GetOpenMPThreadId();
1836 assert(image != (Image *) NULL);
1837 assert(image->signature == MagickSignature);
1838 assert(image->cache != (Cache) NULL);
1839 cache_info=(CacheInfo *) image->cache;
1840 assert(cache_info->signature == MagickSignature);
1841 if (cache_info->methods.get_authentic_pixels_handler !=
1842 (GetAuthenticPixelsHandler) NULL)
1844 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1848 assert(id < (int) cache_info->number_threads);
1849 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1850 cache_info->nexus_info[id],exception);
1855 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1859 + G e t A u t h e n t i c P i x e l s C a c h e %
1863 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1865 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1866 % as defined by the geometry parameters. A pointer to the pixels is returned
1867 % if the pixels are transferred, otherwise a NULL is returned.
1869 % The format of the GetAuthenticPixelsCache() method is:
1871 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1872 % const ssize_t y,const size_t columns,const size_t rows,
1873 % ExceptionInfo *exception)
1875 % A description of each parameter follows:
1877 % o image: the image.
1879 % o x,y,columns,rows: These values define the perimeter of a region of
1882 % o exception: return any errors or warnings in this structure.
1885 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1886 const ssize_t y,const size_t columns,const size_t rows,
1887 ExceptionInfo *exception)
1893 id = GetOpenMPThreadId();
1898 assert(image != (const Image *) NULL);
1899 assert(image->signature == MagickSignature);
1900 assert(image->cache != (Cache) NULL);
1901 cache_info=(CacheInfo *) image->cache;
1902 if (cache_info == (Cache) NULL)
1903 return((Quantum *) NULL);
1904 assert(cache_info->signature == MagickSignature);
1905 assert(id < (int) cache_info->number_threads);
1906 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1907 cache_info->nexus_info[id],exception);
1912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1916 + G e t I m a g e E x t e n t %
1920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1922 % GetImageExtent() returns the extent of the pixels associated corresponding
1923 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1925 % The format of the GetImageExtent() method is:
1927 % MagickSizeType GetImageExtent(const Image *image)
1929 % A description of each parameter follows:
1931 % o image: the image.
1934 MagickExport MagickSizeType GetImageExtent(const Image *image)
1940 id = GetOpenMPThreadId();
1942 assert(image != (Image *) NULL);
1943 assert(image->signature == MagickSignature);
1944 if (image->debug != MagickFalse)
1945 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1946 assert(image->cache != (Cache) NULL);
1947 cache_info=(CacheInfo *) image->cache;
1948 assert(cache_info->signature == MagickSignature);
1949 assert(id < (int) cache_info->number_threads);
1950 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1958 + G e t I m a g e P i x e l C a c h e %
1962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1964 % GetImagePixelCache() ensures that there is only a single reference to the
1965 % pixel cache to be modified, updating the provided cache pointer to point to
1966 % a clone of the original pixel cache if necessary.
1968 % The format of the GetImagePixelCache method is:
1970 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1971 % ExceptionInfo *exception)
1973 % A description of each parameter follows:
1975 % o image: the image.
1977 % o clone: any value other than MagickFalse clones the cache pixels.
1979 % o exception: return any errors or warnings in this structure.
1983 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
1993 Does the image match the pixel cache morphology?
1995 cache_info=(CacheInfo *) image->cache;
1996 p=image->channel_map;
1997 q=cache_info->channel_map;
1998 if ((image->storage_class != cache_info->storage_class) ||
1999 (image->colorspace != cache_info->colorspace) ||
2000 (image->matte != cache_info->matte) ||
2001 (image->columns != cache_info->columns) ||
2002 (image->rows != cache_info->rows) ||
2003 (image->number_channels != cache_info->number_channels) ||
2004 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
2005 (image->metacontent_extent != cache_info->metacontent_extent) ||
2006 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2007 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2008 return(MagickFalse);
2012 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2013 ExceptionInfo *exception)
2022 static MagickSizeType
2028 cache_timestamp = 0;
2031 LockSemaphoreInfo(image->semaphore);
2032 if (cpu_throttle == 0)
2038 Set CPU throttle in milleseconds.
2040 cpu_throttle=MagickResourceInfinity;
2041 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2042 if (limit == (char *) NULL)
2043 limit=GetPolicyValue("throttle");
2044 if (limit != (char *) NULL)
2046 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2047 limit=DestroyString(limit);
2050 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2051 MagickDelay(cpu_throttle);
2052 if (time_limit == 0)
2055 Set the exire time in seconds.
2057 time_limit=GetMagickResourceLimit(TimeResource);
2058 cache_timestamp=time((time_t *) NULL);
2060 if ((time_limit != MagickResourceInfinity) &&
2061 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
2062 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2063 assert(image->cache != (Cache) NULL);
2064 cache_info=(CacheInfo *) image->cache;
2065 destroy=MagickFalse;
2066 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2068 LockSemaphoreInfo(cache_info->semaphore);
2069 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2080 clone_image=(*image);
2081 clone_image.semaphore=AllocateSemaphoreInfo();
2082 clone_image.reference_count=1;
2083 clone_image.cache=ClonePixelCache(cache_info);
2084 clone_info=(CacheInfo *) clone_image.cache;
2085 status=OpenPixelCache(&clone_image,IOMode,exception);
2086 if (status != MagickFalse)
2088 if (clone != MagickFalse)
2089 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2090 if (status != MagickFalse)
2092 if (cache_info->mode == ReadMode)
2093 cache_info->nexus_info=(NexusInfo **) NULL;
2095 image->cache=clone_image.cache;
2098 DestroySemaphoreInfo(&clone_image.semaphore);
2100 UnlockSemaphoreInfo(cache_info->semaphore);
2102 if (destroy != MagickFalse)
2103 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2104 if (status != MagickFalse)
2107 Ensure the image matches the pixel cache morphology.
2109 image->taint=MagickTrue;
2110 image->type=UndefinedType;
2111 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2112 status=OpenPixelCache(image,IOMode,exception);
2114 UnlockSemaphoreInfo(image->semaphore);
2115 if (status == MagickFalse)
2116 return((Cache) NULL);
2117 return(image->cache);
2121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2125 % G e t O n e A u t h e n t i c P i x e l %
2129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2131 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2132 % location. The image background color is returned if an error occurs.
2134 % The format of the GetOneAuthenticPixel() method is:
2136 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2137 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2139 % A description of each parameter follows:
2141 % o image: the image.
2143 % o x,y: These values define the location of the pixel to return.
2145 % o pixel: return a pixel at the specified (x,y) location.
2147 % o exception: return any errors or warnings in this structure.
2150 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2151 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2162 assert(image != (Image *) NULL);
2163 assert(image->signature == MagickSignature);
2164 assert(image->cache != (Cache) NULL);
2165 cache_info=(CacheInfo *) image->cache;
2166 assert(cache_info->signature == MagickSignature);
2167 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2168 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2169 (GetOneAuthenticPixelFromHandler) NULL)
2170 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2172 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2173 if (q == (Quantum *) NULL)
2175 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2176 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2177 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2178 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2179 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2180 return(MagickFalse);
2182 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2187 channel=GetPixelChannelMapChannel(image,i);
2188 pixel[channel]=q[i];
2194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2198 + 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 %
2202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2205 % location. The image background color is returned if an error occurs.
2207 % The format of the GetOneAuthenticPixelFromCache() method is:
2209 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2210 % const ssize_t x,const ssize_t y,Quantum *pixel,
2211 % ExceptionInfo *exception)
2213 % A description of each parameter follows:
2215 % o image: the image.
2217 % o x,y: These values define the location of the pixel to return.
2219 % o pixel: return a pixel at the specified (x,y) location.
2221 % o exception: return any errors or warnings in this structure.
2224 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2225 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2231 id = GetOpenMPThreadId();
2239 assert(image != (const Image *) NULL);
2240 assert(image->signature == MagickSignature);
2241 assert(image->cache != (Cache) NULL);
2242 cache_info=(CacheInfo *) image->cache;
2243 assert(cache_info->signature == MagickSignature);
2244 assert(id < (int) cache_info->number_threads);
2245 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2246 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2248 if (q == (Quantum *) NULL)
2250 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2251 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2252 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2253 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2254 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2255 return(MagickFalse);
2257 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2262 channel=GetPixelChannelMapChannel(image,i);
2263 pixel[channel]=q[i];
2269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2273 % G e t O n e V i r t u a l P i x e l %
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2279 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2280 % (x,y) location. The image background color is returned if an error occurs.
2281 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2283 % The format of the GetOneVirtualPixel() method is:
2285 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2286 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2288 % A description of each parameter follows:
2290 % o image: the image.
2292 % o x,y: These values define the location of the pixel to return.
2294 % o pixel: return a pixel at the specified (x,y) location.
2296 % o exception: return any errors or warnings in this structure.
2299 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2300 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2306 id = GetOpenMPThreadId();
2314 assert(image != (const Image *) NULL);
2315 assert(image->signature == MagickSignature);
2316 assert(image->cache != (Cache) NULL);
2317 cache_info=(CacheInfo *) image->cache;
2318 assert(cache_info->signature == MagickSignature);
2319 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2320 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2321 (GetOneVirtualPixelFromHandler) NULL)
2322 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2323 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2324 assert(id < (int) cache_info->number_threads);
2325 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2326 1UL,1UL,cache_info->nexus_info[id],exception);
2327 if (p == (const Quantum *) NULL)
2329 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2330 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2331 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2332 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2333 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2334 return(MagickFalse);
2336 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2341 channel=GetPixelChannelMapChannel(image,i);
2342 pixel[channel]=p[i];
2348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2352 + 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 %
2356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2358 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2359 % specified (x,y) location. The image background color is returned if an
2362 % The format of the GetOneVirtualPixelFromCache() method is:
2364 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2365 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2366 % Quantum *pixel,ExceptionInfo *exception)
2368 % A description of each parameter follows:
2370 % o image: the image.
2372 % o virtual_pixel_method: the virtual pixel method.
2374 % o x,y: These values define the location of the pixel to return.
2376 % o pixel: return a pixel at the specified (x,y) location.
2378 % o exception: return any errors or warnings in this structure.
2381 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2382 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2383 Quantum *pixel,ExceptionInfo *exception)
2389 id = GetOpenMPThreadId();
2397 assert(image != (const Image *) NULL);
2398 assert(image->signature == MagickSignature);
2399 assert(image->cache != (Cache) NULL);
2400 cache_info=(CacheInfo *) image->cache;
2401 assert(cache_info->signature == MagickSignature);
2402 assert(id < (int) cache_info->number_threads);
2403 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2404 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2405 cache_info->nexus_info[id],exception);
2406 if (p == (const Quantum *) NULL)
2408 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2409 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2410 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2411 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2412 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2413 return(MagickFalse);
2415 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2420 channel=GetPixelChannelMapChannel(image,i);
2421 pixel[channel]=p[i];
2427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2431 % G e t O n e V i r t u a l P i x e l I n f o %
2435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2437 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2438 % location. The image background color is returned if an error occurs. If
2439 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2441 % The format of the GetOneVirtualPixelInfo() method is:
2443 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2444 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2445 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2447 % A description of each parameter follows:
2449 % o image: the image.
2451 % o virtual_pixel_method: the virtual pixel method.
2453 % o x,y: these values define the location of the pixel to return.
2455 % o pixel: return a pixel at the specified (x,y) location.
2457 % o exception: return any errors or warnings in this structure.
2460 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2461 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2462 PixelInfo *pixel,ExceptionInfo *exception)
2468 id = GetOpenMPThreadId();
2470 register const Quantum
2473 assert(image != (const Image *) NULL);
2474 assert(image->signature == MagickSignature);
2475 assert(image->cache != (Cache) NULL);
2476 cache_info=(CacheInfo *) image->cache;
2477 assert(cache_info->signature == MagickSignature);
2478 assert(id < (int) cache_info->number_threads);
2479 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2480 cache_info->nexus_info[id],exception);
2481 GetPixelInfo(image,pixel);
2482 if (p == (const Quantum *) NULL)
2483 return(MagickFalse);
2484 GetPixelInfoPixel(image,p,pixel);
2489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2493 + G e t P i x e l C a c h e C o l o r s p a c e %
2497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2499 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2501 % The format of the GetPixelCacheColorspace() method is:
2503 % Colorspace GetPixelCacheColorspace(Cache cache)
2505 % A description of each parameter follows:
2507 % o cache: the pixel cache.
2510 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2515 assert(cache != (Cache) NULL);
2516 cache_info=(CacheInfo *) cache;
2517 assert(cache_info->signature == MagickSignature);
2518 if (cache_info->debug != MagickFalse)
2519 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2520 cache_info->filename);
2521 return(cache_info->colorspace);
2525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2529 + G e t P i x e l C a c h e M e t h o d s %
2533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2535 % GetPixelCacheMethods() initializes the CacheMethods structure.
2537 % The format of the GetPixelCacheMethods() method is:
2539 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2541 % A description of each parameter follows:
2543 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2546 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2548 assert(cache_methods != (CacheMethods *) NULL);
2549 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2550 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2551 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2552 cache_methods->get_virtual_metacontent_from_handler=
2553 GetVirtualMetacontentFromCache;
2554 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2555 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2556 cache_methods->get_authentic_metacontent_from_handler=
2557 GetAuthenticMetacontentFromCache;
2558 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2559 cache_methods->get_one_authentic_pixel_from_handler=
2560 GetOneAuthenticPixelFromCache;
2561 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2562 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2563 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2571 + G e t P i x e l C a c h e N e x u s E x t e n t %
2575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2577 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2578 % corresponding with the last call to SetPixelCacheNexusPixels() or
2579 % GetPixelCacheNexusPixels().
2581 % The format of the GetPixelCacheNexusExtent() method is:
2583 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2584 % NexusInfo *nexus_info)
2586 % A description of each parameter follows:
2588 % o nexus_info: the nexus info.
2591 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2592 NexusInfo *nexus_info)
2600 assert(cache != NULL);
2601 cache_info=(CacheInfo *) cache;
2602 assert(cache_info->signature == MagickSignature);
2603 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2605 return((MagickSizeType) cache_info->columns*cache_info->rows);
2610 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2614 + 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 %
2618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2620 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2623 % The format of the GetPixelCacheNexusMetacontent() method is:
2625 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2626 % NexusInfo *nexus_info)
2628 % A description of each parameter follows:
2630 % o cache: the pixel cache.
2632 % o nexus_info: the cache nexus to return the meta-content.
2635 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2636 NexusInfo *nexus_info)
2641 assert(cache != NULL);
2642 cache_info=(CacheInfo *) cache;
2643 assert(cache_info->signature == MagickSignature);
2644 if (cache_info->storage_class == UndefinedClass)
2645 return((void *) NULL);
2646 return(nexus_info->metacontent);
2650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2654 + G e t P i x e l C a c h e N e x u s P i x e l s %
2658 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2660 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2663 % The format of the GetPixelCacheNexusPixels() method is:
2665 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2666 % NexusInfo *nexus_info)
2668 % A description of each parameter follows:
2670 % o cache: the pixel cache.
2672 % o nexus_info: the cache nexus to return the pixels.
2675 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2676 NexusInfo *nexus_info)
2681 assert(cache != NULL);
2682 cache_info=(CacheInfo *) cache;
2683 assert(cache_info->signature == MagickSignature);
2684 if (cache_info->storage_class == UndefinedClass)
2685 return((Quantum *) NULL);
2686 return(nexus_info->pixels);
2690 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2694 + G e t P i x e l C a c h e P i x e l s %
2698 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2700 % GetPixelCachePixels() returns the pixels associated with the specified image.
2702 % The format of the GetPixelCachePixels() method is:
2704 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2705 % ExceptionInfo *exception)
2707 % A description of each parameter follows:
2709 % o image: the image.
2711 % o length: the pixel cache length.
2713 % o exception: return any errors or warnings in this structure.
2716 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2717 ExceptionInfo *exception)
2722 assert(image != (const Image *) NULL);
2723 assert(image->signature == MagickSignature);
2724 assert(image->cache != (Cache) NULL);
2725 assert(length != (MagickSizeType *) NULL);
2726 assert(exception != (ExceptionInfo *) NULL);
2727 assert(exception->signature == MagickSignature);
2728 cache_info=(CacheInfo *) image->cache;
2729 assert(cache_info->signature == MagickSignature);
2731 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2732 return((void *) NULL);
2733 *length=cache_info->length;
2734 return((void *) cache_info->pixels);
2738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2742 + 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 %
2746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2748 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2750 % The format of the GetPixelCacheStorageClass() method is:
2752 % ClassType GetPixelCacheStorageClass(Cache cache)
2754 % A description of each parameter follows:
2756 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2758 % o cache: the pixel cache.
2761 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2766 assert(cache != (Cache) NULL);
2767 cache_info=(CacheInfo *) cache;
2768 assert(cache_info->signature == MagickSignature);
2769 if (cache_info->debug != MagickFalse)
2770 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2771 cache_info->filename);
2772 return(cache_info->storage_class);
2776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2780 + G e t P i x e l C a c h e T i l e S i z e %
2784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2786 % GetPixelCacheTileSize() returns the pixel cache tile size.
2788 % The format of the GetPixelCacheTileSize() method is:
2790 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2793 % A description of each parameter follows:
2795 % o image: the image.
2797 % o width: the optimize cache tile width in pixels.
2799 % o height: the optimize cache tile height in pixels.
2802 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2808 assert(image != (Image *) NULL);
2809 assert(image->signature == MagickSignature);
2810 if (image->debug != MagickFalse)
2811 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2812 cache_info=(CacheInfo *) image->cache;
2813 assert(cache_info->signature == MagickSignature);
2814 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2815 if (GetPixelCacheType(image) == DiskCache)
2816 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2825 + G e t P i x e l C a c h e T y p e %
2829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2831 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2833 % The format of the GetPixelCacheType() method is:
2835 % CacheType GetPixelCacheType(const Image *image)
2837 % A description of each parameter follows:
2839 % o image: the image.
2842 MagickPrivate CacheType GetPixelCacheType(const Image *image)
2847 assert(image != (Image *) NULL);
2848 assert(image->signature == MagickSignature);
2849 assert(image->cache != (Cache) NULL);
2850 cache_info=(CacheInfo *) image->cache;
2851 assert(cache_info->signature == MagickSignature);
2852 return(cache_info->type);
2856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2860 + 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 %
2864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2866 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2867 % pixel cache. A virtual pixel is any pixel access that is outside the
2868 % boundaries of the image cache.
2870 % The format of the GetPixelCacheVirtualMethod() method is:
2872 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2874 % A description of each parameter follows:
2876 % o image: the image.
2879 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2884 assert(image != (Image *) NULL);
2885 assert(image->signature == MagickSignature);
2886 assert(image->cache != (Cache) NULL);
2887 cache_info=(CacheInfo *) image->cache;
2888 assert(cache_info->signature == MagickSignature);
2889 return(cache_info->virtual_pixel_method);
2893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2897 + 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 %
2901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2903 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2904 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2906 % The format of the GetVirtualMetacontentFromCache() method is:
2908 % void *GetVirtualMetacontentFromCache(const Image *image)
2910 % A description of each parameter follows:
2912 % o image: the image.
2915 static const void *GetVirtualMetacontentFromCache(const Image *image)
2921 id = GetOpenMPThreadId();
2926 assert(image != (const Image *) NULL);
2927 assert(image->signature == MagickSignature);
2928 assert(image->cache != (Cache) NULL);
2929 cache_info=(CacheInfo *) image->cache;
2930 assert(cache_info->signature == MagickSignature);
2931 assert(id < (int) cache_info->number_threads);
2932 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2933 cache_info->nexus_info[id]);
2934 return(metacontent);
2938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2942 + 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 %
2946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2948 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2951 % The format of the GetVirtualMetacontentFromNexus() method is:
2953 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2954 % NexusInfo *nexus_info)
2956 % A description of each parameter follows:
2958 % o cache: the pixel cache.
2960 % o nexus_info: the cache nexus to return the meta-content.
2963 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2964 NexusInfo *nexus_info)
2969 assert(cache != (Cache) NULL);
2970 cache_info=(CacheInfo *) cache;
2971 assert(cache_info->signature == MagickSignature);
2972 if (cache_info->storage_class == UndefinedClass)
2973 return((void *) NULL);
2974 return(nexus_info->metacontent);
2978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2982 % G e t V i r t u a l M e t a c o n t e n t %
2986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2988 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2989 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
2990 % returned if the meta-content are not available.
2992 % The format of the GetVirtualMetacontent() method is:
2994 % const void *GetVirtualMetacontent(const Image *image)
2996 % A description of each parameter follows:
2998 % o image: the image.
3001 MagickExport const void *GetVirtualMetacontent(const Image *image)
3007 id = GetOpenMPThreadId();
3012 assert(image != (const Image *) NULL);
3013 assert(image->signature == MagickSignature);
3014 assert(image->cache != (Cache) NULL);
3015 cache_info=(CacheInfo *) image->cache;
3016 assert(cache_info->signature == MagickSignature);
3017 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3018 (GetVirtualMetacontentFromHandler) NULL)
3020 metacontent=cache_info->methods.
3021 get_virtual_metacontent_from_handler(image);
3022 return(metacontent);
3024 assert(id < (int) cache_info->number_threads);
3025 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3026 cache_info->nexus_info[id]);
3027 return(metacontent);
3031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3035 + 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 %
3039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3041 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3042 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3043 % is returned if the pixels are transferred, otherwise a NULL is returned.
3045 % The format of the GetVirtualPixelsFromNexus() method is:
3047 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
3048 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3049 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
3050 % ExceptionInfo *exception)
3052 % A description of each parameter follows:
3054 % o image: the image.
3056 % o virtual_pixel_method: the virtual pixel method.
3058 % o x,y,columns,rows: These values define the perimeter of a region of
3061 % o nexus_info: the cache nexus to acquire.
3063 % o exception: return any errors or warnings in this structure.
3070 0, 48, 12, 60, 3, 51, 15, 63,
3071 32, 16, 44, 28, 35, 19, 47, 31,
3072 8, 56, 4, 52, 11, 59, 7, 55,
3073 40, 24, 36, 20, 43, 27, 39, 23,
3074 2, 50, 14, 62, 1, 49, 13, 61,
3075 34, 18, 46, 30, 33, 17, 45, 29,
3076 10, 58, 6, 54, 9, 57, 5, 53,
3077 42, 26, 38, 22, 41, 25, 37, 21
3080 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3085 index=x+DitherMatrix[x & 0x07]-32L;
3088 if (index >= (ssize_t) columns)
3089 return((ssize_t) columns-1L);
3093 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3098 index=y+DitherMatrix[y & 0x07]-32L;
3101 if (index >= (ssize_t) rows)
3102 return((ssize_t) rows-1L);
3106 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3110 if (x >= (ssize_t) columns)
3111 return((ssize_t) (columns-1));
3115 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3119 if (y >= (ssize_t) rows)
3120 return((ssize_t) (rows-1));
3124 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3126 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3129 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3131 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3134 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3135 const size_t extent)
3141 Compute the remainder of dividing offset by extent. It returns not only
3142 the quotient (tile the offset falls in) but also the positive remainer
3143 within that tile such that 0 <= remainder < extent. This method is
3144 essentially a ldiv() using a floored modulo division rather than the
3145 normal default truncated modulo division.
3147 modulo.quotient=offset/(ssize_t) extent;
3150 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3154 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3155 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3156 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3157 ExceptionInfo *exception)
3174 virtual_pixel[CompositePixelChannel];
3179 register const Quantum
3192 register unsigned char
3199 *virtual_metacontent;
3204 assert(image != (const Image *) NULL);
3205 assert(image->signature == MagickSignature);
3206 assert(image->cache != (Cache) NULL);
3207 cache_info=(CacheInfo *) image->cache;
3208 assert(cache_info->signature == MagickSignature);
3209 if (cache_info->type == UndefinedCache)
3210 return((const Quantum *) NULL);
3213 region.width=columns;
3215 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3216 if (pixels == (Quantum *) NULL)
3217 return((const Quantum *) NULL);
3219 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3220 nexus_info->region.x;
3221 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3222 nexus_info->region.width-1L;
3223 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3224 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3225 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3226 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3232 Pixel request is inside cache extents.
3234 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3236 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3237 if (status == MagickFalse)
3238 return((const Quantum *) NULL);
3239 if (cache_info->metacontent_extent != 0)
3241 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3242 if (status == MagickFalse)
3243 return((const Quantum *) NULL);
3248 Pixel request is outside cache extents.
3250 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3251 virtual_nexus=AcquirePixelCacheNexus(1);
3252 if (virtual_nexus == (NexusInfo **) NULL)
3254 if (virtual_nexus != (NexusInfo **) NULL)
3255 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3256 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3257 "UnableToGetCacheNexus","`%s'",image->filename);
3258 return((const Quantum *) NULL);
3260 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3261 sizeof(*virtual_pixel));
3262 virtual_metacontent=(void *) NULL;
3263 switch (virtual_pixel_method)
3265 case BackgroundVirtualPixelMethod:
3266 case BlackVirtualPixelMethod:
3267 case GrayVirtualPixelMethod:
3268 case TransparentVirtualPixelMethod:
3269 case MaskVirtualPixelMethod:
3270 case WhiteVirtualPixelMethod:
3271 case EdgeVirtualPixelMethod:
3272 case CheckerTileVirtualPixelMethod:
3273 case HorizontalTileVirtualPixelMethod:
3274 case VerticalTileVirtualPixelMethod:
3276 if (cache_info->metacontent_extent != 0)
3279 Acquire a metacontent buffer.
3281 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3282 cache_info->metacontent_extent);
3283 if (virtual_metacontent == (void *) NULL)
3285 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3286 (void) ThrowMagickException(exception,GetMagickModule(),
3287 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3288 return((const Quantum *) NULL);
3290 (void) ResetMagickMemory(virtual_metacontent,0,
3291 cache_info->metacontent_extent);
3293 switch (virtual_pixel_method)
3295 case BlackVirtualPixelMethod:
3297 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3298 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3299 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3302 case GrayVirtualPixelMethod:
3304 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3305 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3307 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3310 case TransparentVirtualPixelMethod:
3312 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3313 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3314 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3317 case MaskVirtualPixelMethod:
3318 case WhiteVirtualPixelMethod:
3320 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3321 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3322 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3327 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3329 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3331 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3333 if (image->colorspace == CMYKColorspace)
3334 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3336 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3346 for (v=0; v < (ssize_t) rows; v++)
3348 for (u=0; u < (ssize_t) columns; u+=length)
3350 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3351 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3352 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3360 Transfer a single pixel.
3362 length=(MagickSizeType) 1;
3363 switch (virtual_pixel_method)
3367 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3368 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3369 1UL,1UL,*virtual_nexus,exception);
3370 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3373 case RandomVirtualPixelMethod:
3375 if (cache_info->random_info == (RandomInfo *) NULL)
3376 cache_info->random_info=AcquireRandomInfo();
3377 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3378 RandomX(cache_info->random_info,cache_info->columns),
3379 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3380 *virtual_nexus,exception);
3381 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3384 case DitherVirtualPixelMethod:
3386 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3387 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3388 1UL,1UL,*virtual_nexus,exception);
3389 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3392 case TileVirtualPixelMethod:
3394 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3395 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3396 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3397 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3399 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3402 case MirrorVirtualPixelMethod:
3404 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3405 if ((x_modulo.quotient & 0x01) == 1L)
3406 x_modulo.remainder=(ssize_t) cache_info->columns-
3407 x_modulo.remainder-1L;
3408 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3409 if ((y_modulo.quotient & 0x01) == 1L)
3410 y_modulo.remainder=(ssize_t) cache_info->rows-
3411 y_modulo.remainder-1L;
3412 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3413 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3415 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3418 case HorizontalTileEdgeVirtualPixelMethod:
3420 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3421 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3422 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3423 *virtual_nexus,exception);
3424 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3427 case VerticalTileEdgeVirtualPixelMethod:
3429 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3431 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3432 *virtual_nexus,exception);
3433 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3436 case BackgroundVirtualPixelMethod:
3437 case BlackVirtualPixelMethod:
3438 case GrayVirtualPixelMethod:
3439 case TransparentVirtualPixelMethod:
3440 case MaskVirtualPixelMethod:
3441 case WhiteVirtualPixelMethod:
3444 r=virtual_metacontent;
3447 case EdgeVirtualPixelMethod:
3448 case CheckerTileVirtualPixelMethod:
3450 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3451 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3452 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3455 r=virtual_metacontent;
3458 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3459 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3461 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3464 case HorizontalTileVirtualPixelMethod:
3466 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3469 r=virtual_metacontent;
3472 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3473 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3474 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3475 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3477 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3480 case VerticalTileVirtualPixelMethod:
3482 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3485 r=virtual_metacontent;
3488 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3489 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3490 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3491 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3493 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3497 if (p == (const Quantum *) NULL)
3499 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3501 q+=cache_info->number_channels;
3502 if ((s != (void *) NULL) && (r != (const void *) NULL))
3504 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3505 s+=cache_info->metacontent_extent;
3510 Transfer a run of pixels.
3512 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3513 length,1UL,*virtual_nexus,exception);
3514 if (p == (const Quantum *) NULL)
3516 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3517 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3518 q+=length*cache_info->number_channels;
3519 if ((r != (void *) NULL) && (s != (const void *) NULL))
3521 (void) memcpy(s,r,(size_t) length);
3522 s+=length*cache_info->metacontent_extent;
3529 if (virtual_metacontent != (void *) NULL)
3530 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3531 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3540 + G e t V i r t u a l P i x e l C a c h e %
3544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3546 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3547 % cache as defined by the geometry parameters. A pointer to the pixels
3548 % is returned if the pixels are transferred, otherwise a NULL is returned.
3550 % The format of the GetVirtualPixelCache() method is:
3552 % const Quantum *GetVirtualPixelCache(const Image *image,
3553 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3554 % const ssize_t y,const size_t columns,const size_t rows,
3555 % ExceptionInfo *exception)
3557 % A description of each parameter follows:
3559 % o image: the image.
3561 % o virtual_pixel_method: the virtual pixel method.
3563 % o x,y,columns,rows: These values define the perimeter of a region of
3566 % o exception: return any errors or warnings in this structure.
3569 static const Quantum *GetVirtualPixelCache(const Image *image,
3570 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3571 const size_t columns,const size_t rows,ExceptionInfo *exception)
3577 id = GetOpenMPThreadId();
3582 assert(image != (const Image *) NULL);
3583 assert(image->signature == MagickSignature);
3584 assert(image->cache != (Cache) NULL);
3585 cache_info=(CacheInfo *) image->cache;
3586 assert(cache_info->signature == MagickSignature);
3587 assert(id < (int) cache_info->number_threads);
3588 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3589 cache_info->nexus_info[id],exception);
3594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3598 % G e t V i r t u a l P i x e l Q u e u e %
3602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3604 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3605 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3607 % The format of the GetVirtualPixelQueue() method is:
3609 % const Quantum *GetVirtualPixelQueue(const Image image)
3611 % A description of each parameter follows:
3613 % o image: the image.
3616 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3622 id = GetOpenMPThreadId();
3624 assert(image != (const Image *) NULL);
3625 assert(image->signature == MagickSignature);
3626 assert(image->cache != (Cache) NULL);
3627 cache_info=(CacheInfo *) image->cache;
3628 assert(cache_info->signature == MagickSignature);
3629 if (cache_info->methods.get_virtual_pixels_handler !=
3630 (GetVirtualPixelsHandler) NULL)
3631 return(cache_info->methods.get_virtual_pixels_handler(image));
3632 assert(id < (int) cache_info->number_threads);
3633 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3641 % G e t V i r t u a l P i x e l s %
3645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3647 % GetVirtualPixels() returns an immutable pixel region. If the
3648 % region is successfully accessed, a pointer to it is returned, otherwise
3649 % NULL is returned. The returned pointer may point to a temporary working
3650 % copy of the pixels or it may point to the original pixels in memory.
3651 % Performance is maximized if the selected region is part of one row, or one
3652 % or more full rows, since there is opportunity to access the pixels in-place
3653 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3654 % returned pointer must *never* be deallocated by the user.
3656 % Pixels accessed via the returned pointer represent a simple array of type
3657 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3658 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3659 % access the meta-content (of type void) corresponding to the the
3662 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3664 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3665 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3666 % GetCacheViewAuthenticPixels() instead.
3668 % The format of the GetVirtualPixels() method is:
3670 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3671 % const ssize_t y,const size_t columns,const size_t rows,
3672 % ExceptionInfo *exception)
3674 % A description of each parameter follows:
3676 % o image: the image.
3678 % o x,y,columns,rows: These values define the perimeter of a region of
3681 % o exception: return any errors or warnings in this structure.
3684 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3685 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3686 ExceptionInfo *exception)
3692 id = GetOpenMPThreadId();
3697 assert(image != (const Image *) NULL);
3698 assert(image->signature == MagickSignature);
3699 assert(image->cache != (Cache) NULL);
3700 cache_info=(CacheInfo *) image->cache;
3701 assert(cache_info->signature == MagickSignature);
3702 if (cache_info->methods.get_virtual_pixel_handler !=
3703 (GetVirtualPixelHandler) NULL)
3704 return(cache_info->methods.get_virtual_pixel_handler(image,
3705 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3706 assert(id < (int) cache_info->number_threads);
3707 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3708 columns,rows,cache_info->nexus_info[id],exception);
3713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3717 + 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 %
3721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3723 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3724 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3726 % The format of the GetVirtualPixelsCache() method is:
3728 % Quantum *GetVirtualPixelsCache(const Image *image)
3730 % A description of each parameter follows:
3732 % o image: the image.
3735 static const Quantum *GetVirtualPixelsCache(const Image *image)
3741 id = GetOpenMPThreadId();
3743 assert(image != (const Image *) NULL);
3744 assert(image->signature == MagickSignature);
3745 assert(image->cache != (Cache) NULL);
3746 cache_info=(CacheInfo *) image->cache;
3747 assert(cache_info->signature == MagickSignature);
3748 assert(id < (int) cache_info->number_threads);
3749 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3757 + G e t V i r t u a l P i x e l s N e x u s %
3761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3763 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3766 % The format of the GetVirtualPixelsNexus() method is:
3768 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3769 % NexusInfo *nexus_info)
3771 % A description of each parameter follows:
3773 % o cache: the pixel cache.
3775 % o nexus_info: the cache nexus to return the colormap pixels.
3778 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3779 NexusInfo *nexus_info)
3784 assert(cache != (Cache) NULL);
3785 cache_info=(CacheInfo *) cache;
3786 assert(cache_info->signature == MagickSignature);
3787 if (cache_info->storage_class == UndefinedClass)
3788 return((Quantum *) NULL);
3789 return((const Quantum *) nexus_info->pixels);
3793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3797 + M a s k P i x e l C a c h e N e x u s %
3801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3803 % MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3804 % The method returns MagickTrue if the pixel region is masked, otherwise
3807 % The format of the MaskPixelCacheNexus() method is:
3809 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3810 % NexusInfo *nexus_info,ExceptionInfo *exception)
3812 % A description of each parameter follows:
3814 % o image: the image.
3816 % o nexus_info: the cache nexus to clip.
3818 % o exception: return any errors or warnings in this structure.
3822 static inline void MaskPixelOver(const PixelInfo *p,const MagickRealType alpha,
3823 const PixelInfo *q,const MagickRealType beta,PixelInfo *composite)
3828 if (fabs(alpha-TransparentAlpha) < MagickEpsilon)
3833 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3834 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3835 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3836 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3837 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3838 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3839 composite->black=gamma*MagickOver_(p->black,alpha,q->black,beta);
3842 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3843 ExceptionInfo *exception)
3859 register const Quantum
3872 if (image->debug != MagickFalse)
3873 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3874 if (image->mask == (Image *) NULL)
3875 return(MagickFalse);
3876 cache_info=(CacheInfo *) image->cache;
3877 if (cache_info == (Cache) NULL)
3878 return(MagickFalse);
3879 image_nexus=AcquirePixelCacheNexus(1);
3880 clip_nexus=AcquirePixelCacheNexus(1);
3881 if ((image_nexus == (NexusInfo **) NULL) ||
3882 (clip_nexus == (NexusInfo **) NULL))
3883 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3884 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3885 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3886 nexus_info->region.height,image_nexus[0],exception);
3887 q=nexus_info->pixels;
3888 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3889 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3890 nexus_info->region.height,clip_nexus[0],exception);
3891 GetPixelInfo(image,&alpha);
3892 GetPixelInfo(image,&beta);
3893 number_pixels=(MagickSizeType) nexus_info->region.width*
3894 nexus_info->region.height;
3895 for (i=0; i < (ssize_t) number_pixels; i++)
3897 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
3899 GetPixelInfoPixel(image,p,&alpha);
3900 GetPixelInfoPixel(image,q,&beta);
3901 MaskPixelOver(&beta,(MagickRealType) GetPixelIntensity(image,r),
3902 &alpha,alpha.alpha,&beta);
3903 SetPixelRed(image,ClampToQuantum(beta.red),q);
3904 SetPixelGreen(image,ClampToQuantum(beta.green),q);
3905 SetPixelBlue(image,ClampToQuantum(beta.blue),q);
3906 if (cache_info->colorspace == CMYKColorspace)
3907 SetPixelBlack(image,ClampToQuantum(beta.black),q);
3908 SetPixelAlpha(image,ClampToQuantum(beta.alpha),q);
3913 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3914 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3915 if (i < (ssize_t) number_pixels)
3916 return(MagickFalse);
3921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3925 + O p e n P i x e l C a c h e %
3929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3931 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3932 % dimensions, allocating space for the image pixels and optionally the
3933 % metacontent, and memory mapping the cache if it is disk based. The cache
3934 % nexus array is initialized as well.
3936 % The format of the OpenPixelCache() method is:
3938 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3939 % ExceptionInfo *exception)
3941 % A description of each parameter follows:
3943 % o image: the image.
3945 % o mode: ReadMode, WriteMode, or IOMode.
3947 % o exception: return any errors or warnings in this structure.
3951 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3953 cache_info->mapped=MagickFalse;
3954 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3955 cache_info->length);
3956 if (cache_info->pixels == (Quantum *) NULL)
3958 cache_info->mapped=MagickTrue;
3959 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3960 cache_info->length);
3964 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3974 cache_info=(CacheInfo *) image->cache;
3975 if (image->debug != MagickFalse)
3978 format[MaxTextExtent],
3979 message[MaxTextExtent];
3981 (void) FormatMagickSize(length,MagickFalse,format);
3982 (void) FormatLocaleString(message,MaxTextExtent,
3983 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3984 cache_info->cache_filename,cache_info->file,format);
3985 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3987 if (length != (MagickSizeType) ((MagickOffsetType) length))
3988 return(MagickFalse);
3989 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3991 return(MagickFalse);
3992 if ((MagickSizeType) extent >= length)
3994 offset=(MagickOffsetType) length-1;
3995 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3996 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3999 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4000 ExceptionInfo *exception)
4007 format[MaxTextExtent],
4008 message[MaxTextExtent];
4025 assert(image != (const Image *) NULL);
4026 assert(image->signature == MagickSignature);
4027 assert(image->cache != (Cache) NULL);
4028 if (image->debug != MagickFalse)
4029 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4030 if ((image->columns == 0) || (image->rows == 0))
4031 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4032 cache_info=(CacheInfo *) image->cache;
4033 assert(cache_info->signature == MagickSignature);
4034 source_info=(*cache_info);
4035 source_info.file=(-1);
4036 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4037 image->filename,(double) GetImageIndexInList(image));
4038 cache_info->storage_class=image->storage_class;
4039 cache_info->colorspace=image->colorspace;
4040 cache_info->matte=image->matte;
4041 cache_info->rows=image->rows;
4042 cache_info->columns=image->columns;
4043 InitializePixelChannelMap(image);
4044 cache_info->number_channels=GetPixelChannels(image);
4045 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4046 sizeof(*image->channel_map));
4047 cache_info->metacontent_extent=image->metacontent_extent;
4048 cache_info->mode=mode;
4049 if (image->ping != MagickFalse)
4051 cache_info->type=PingCache;
4052 cache_info->pixels=(Quantum *) NULL;
4053 cache_info->metacontent=(void *) NULL;
4054 cache_info->length=0;
4057 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4058 packet_size=cache_info->number_channels*sizeof(Quantum);
4059 if (image->metacontent_extent != 0)
4060 packet_size+=cache_info->metacontent_extent;
4061 length=number_pixels*packet_size;
4062 columns=(size_t) (length/cache_info->rows/packet_size);
4063 if (cache_info->columns != columns)
4064 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4066 cache_info->length=length;
4067 p=cache_info->channel_map;
4068 q=source_info.channel_map;
4069 if ((cache_info->type != UndefinedCache) &&
4070 (cache_info->columns <= source_info.columns) &&
4071 (cache_info->rows <= source_info.rows) &&
4072 (cache_info->number_channels <= source_info.number_channels) &&
4073 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
4074 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4077 Inline pixel cache clone optimization.
4079 if ((cache_info->columns == source_info.columns) &&
4080 (cache_info->rows == source_info.rows) &&
4081 (cache_info->number_channels == source_info.number_channels) &&
4082 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
4083 (cache_info->metacontent_extent == source_info.metacontent_extent))
4085 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4087 status=AcquireMagickResource(AreaResource,cache_info->length);
4088 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4089 cache_info->metacontent_extent);
4090 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4092 status=AcquireMagickResource(MemoryResource,cache_info->length);
4093 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4094 (cache_info->type == MemoryCache))
4096 AllocatePixelCachePixels(cache_info);
4097 if (cache_info->pixels == (Quantum *) NULL)
4098 cache_info->pixels=source_info.pixels;
4102 Create memory pixel cache.
4105 if (image->debug != MagickFalse)
4107 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
4108 (void) FormatLocaleString(message,MaxTextExtent,
4109 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4110 cache_info->filename,cache_info->mapped != MagickFalse ?
4111 "anonymous" : "heap",(double) cache_info->columns,(double)
4112 cache_info->rows,(double) cache_info->number_channels,
4114 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4117 cache_info->type=MemoryCache;
4118 cache_info->metacontent=(void *) NULL;
4119 if (cache_info->metacontent_extent != 0)
4120 cache_info->metacontent=(void *) (cache_info->pixels+
4121 number_pixels*cache_info->number_channels);
4122 if ((source_info.storage_class != UndefinedClass) &&
4125 status=ClonePixelCachePixels(cache_info,&source_info,
4127 RelinquishPixelCachePixels(&source_info);
4132 RelinquishMagickResource(MemoryResource,cache_info->length);
4135 Create pixel cache on disk.
4137 status=AcquireMagickResource(DiskResource,cache_info->length);
4138 if (status == MagickFalse)
4140 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4141 "CacheResourcesExhausted","`%s'",image->filename);
4142 return(MagickFalse);
4144 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4146 (void) ClosePixelCacheOnDisk(cache_info);
4147 *cache_info->cache_filename='\0';
4149 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4151 RelinquishMagickResource(DiskResource,cache_info->length);
4152 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4154 return(MagickFalse);
4156 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4157 cache_info->length);
4158 if (status == MagickFalse)
4160 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4162 return(MagickFalse);
4164 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4165 cache_info->metacontent_extent);
4166 if (length != (MagickSizeType) ((size_t) length))
4167 cache_info->type=DiskCache;
4170 status=AcquireMagickResource(MapResource,cache_info->length);
4171 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4172 (cache_info->type != MemoryCache))
4173 cache_info->type=DiskCache;
4176 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4177 cache_info->offset,(size_t) cache_info->length);
4178 if (cache_info->pixels == (Quantum *) NULL)
4180 cache_info->type=DiskCache;
4181 cache_info->pixels=source_info.pixels;
4186 Create file-backed memory-mapped pixel cache.
4189 (void) ClosePixelCacheOnDisk(cache_info);
4190 cache_info->type=MapCache;
4191 cache_info->mapped=MagickTrue;
4192 cache_info->metacontent=(void *) NULL;
4193 if (cache_info->metacontent_extent != 0)
4194 cache_info->metacontent=(void *) (cache_info->pixels+
4195 number_pixels*cache_info->number_channels);
4196 if ((source_info.storage_class != UndefinedClass) &&
4199 status=ClonePixelCachePixels(cache_info,&source_info,
4201 RelinquishPixelCachePixels(&source_info);
4203 if (image->debug != MagickFalse)
4205 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
4206 (void) FormatLocaleString(message,MaxTextExtent,
4207 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4208 cache_info->filename,cache_info->cache_filename,
4209 cache_info->file,(double) cache_info->columns,(double)
4210 cache_info->rows,(double) cache_info->number_channels,
4212 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4218 RelinquishMagickResource(MapResource,cache_info->length);
4221 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4223 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4224 RelinquishPixelCachePixels(&source_info);
4226 if (image->debug != MagickFalse)
4228 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4229 (void) FormatLocaleString(message,MaxTextExtent,
4230 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4231 cache_info->cache_filename,cache_info->file,(double)
4232 cache_info->columns,(double) cache_info->rows,(double)
4233 cache_info->number_channels,format);
4234 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4244 + P e r s i s t P i x e l C a c h e %
4248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4250 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4251 % persistent pixel cache is one that resides on disk and is not destroyed
4252 % when the program exits.
4254 % The format of the PersistPixelCache() method is:
4256 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4257 % const MagickBooleanType attach,MagickOffsetType *offset,
4258 % ExceptionInfo *exception)
4260 % A description of each parameter follows:
4262 % o image: the image.
4264 % o filename: the persistent pixel cache filename.
4266 % o attach: A value other than zero initializes the persistent pixel cache.
4268 % o initialize: A value other than zero initializes the persistent pixel
4271 % o offset: the offset in the persistent cache to store pixels.
4273 % o exception: return any errors or warnings in this structure.
4276 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4277 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4278 ExceptionInfo *exception)
4293 assert(image != (Image *) NULL);
4294 assert(image->signature == MagickSignature);
4295 if (image->debug != MagickFalse)
4296 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4297 assert(image->cache != (void *) NULL);
4298 assert(filename != (const char *) NULL);
4299 assert(offset != (MagickOffsetType *) NULL);
4300 page_size=GetMagickPageSize();
4301 cache_info=(CacheInfo *) image->cache;
4302 assert(cache_info->signature == MagickSignature);
4303 if (attach != MagickFalse)
4306 Attach existing persistent pixel cache.
4308 if (image->debug != MagickFalse)
4309 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4310 "attach persistent cache");
4311 (void) CopyMagickString(cache_info->cache_filename,filename,
4313 cache_info->type=DiskCache;
4314 cache_info->offset=(*offset);
4315 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4316 return(MagickFalse);
4317 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4320 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4321 (cache_info->reference_count == 1))
4323 LockSemaphoreInfo(cache_info->semaphore);
4324 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4325 (cache_info->reference_count == 1))
4331 Usurp existing persistent pixel cache.
4333 status=rename_utf8(cache_info->cache_filename,filename);
4336 (void) CopyMagickString(cache_info->cache_filename,filename,
4338 *offset+=cache_info->length+page_size-(cache_info->length %
4340 UnlockSemaphoreInfo(cache_info->semaphore);
4341 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4342 if (image->debug != MagickFalse)
4343 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4344 "Usurp resident persistent cache");
4348 UnlockSemaphoreInfo(cache_info->semaphore);
4351 Clone persistent pixel cache.
4353 clone_image=(*image);
4354 clone_info=(CacheInfo *) clone_image.cache;
4355 image->cache=ClonePixelCache(cache_info);
4356 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4357 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4358 cache_info->type=DiskCache;
4359 cache_info->offset=(*offset);
4360 cache_info=(CacheInfo *) image->cache;
4361 status=OpenPixelCache(image,IOMode,exception);
4362 if (status != MagickFalse)
4363 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4364 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4365 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4374 + Q u e u e A u t h e n t i c N e x u s %
4378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4380 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4381 % by the region rectangle and returns a pointer to the region. This region is
4382 % subsequently transferred from the pixel cache with
4383 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4384 % pixels are transferred, otherwise a NULL is returned.
4386 % The format of the QueueAuthenticNexus() method is:
4388 % Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4389 % const ssize_t y,const size_t columns,const size_t rows,
4390 % const MagickBooleanType clone,NexusInfo *nexus_info,
4391 % ExceptionInfo *exception)
4393 % A description of each parameter follows:
4395 % o image: the image.
4397 % o x,y,columns,rows: These values define the perimeter of a region of
4400 % o nexus_info: the cache nexus to set.
4402 % o clone: clone the pixel cache.
4404 % o exception: return any errors or warnings in this structure.
4407 MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4408 const ssize_t y,const size_t columns,const size_t rows,
4409 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4424 Validate pixel cache geometry.
4426 assert(image != (const Image *) NULL);
4427 assert(image->signature == MagickSignature);
4428 assert(image->cache != (Cache) NULL);
4429 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4430 if (cache_info == (Cache) NULL)
4431 return((Quantum *) NULL);
4432 assert(cache_info->signature == MagickSignature);
4433 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4435 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4436 "NoPixelsDefinedInCache","`%s'",image->filename);
4437 return((Quantum *) NULL);
4439 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4440 (y >= (ssize_t) cache_info->rows))
4442 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4443 "PixelsAreNotAuthentic","`%s'",image->filename);
4444 return((Quantum *) NULL);
4446 offset=(MagickOffsetType) y*cache_info->columns+x;
4448 return((Quantum *) NULL);
4449 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4450 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4451 if ((MagickSizeType) offset >= number_pixels)
4452 return((Quantum *) NULL);
4458 region.width=columns;
4460 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4464 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4468 + 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 %
4472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4474 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4475 % defined by the region rectangle and returns a pointer to the region. This
4476 % region is subsequently transferred from the pixel cache with
4477 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4478 % pixels are transferred, otherwise a NULL is returned.
4480 % The format of the QueueAuthenticPixelsCache() method is:
4482 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4483 % const ssize_t y,const size_t columns,const size_t rows,
4484 % ExceptionInfo *exception)
4486 % A description of each parameter follows:
4488 % o image: the image.
4490 % o x,y,columns,rows: These values define the perimeter of a region of
4493 % o exception: return any errors or warnings in this structure.
4496 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4497 const ssize_t y,const size_t columns,const size_t rows,
4498 ExceptionInfo *exception)
4504 id = GetOpenMPThreadId();
4509 assert(image != (const Image *) NULL);
4510 assert(image->signature == MagickSignature);
4511 assert(image->cache != (Cache) NULL);
4512 cache_info=(CacheInfo *) image->cache;
4513 assert(cache_info->signature == MagickSignature);
4514 assert(id < (int) cache_info->number_threads);
4515 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4516 cache_info->nexus_info[id],exception);
4521 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4525 % Q u e u e A u t h e n t i c P i x e l s %
4529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4531 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4532 % successfully initialized a pointer to a Quantum array representing the
4533 % region is returned, otherwise NULL is returned. The returned pointer may
4534 % point to a temporary working buffer for the pixels or it may point to the
4535 % final location of the pixels in memory.
4537 % Write-only access means that any existing pixel values corresponding to
4538 % the region are ignored. This is useful if the initial image is being
4539 % created from scratch, or if the existing pixel values are to be
4540 % completely replaced without need to refer to their pre-existing values.
4541 % The application is free to read and write the pixel buffer returned by
4542 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4543 % initialize the pixel array values. Initializing pixel array values is the
4544 % application's responsibility.
4546 % Performance is maximized if the selected region is part of one row, or
4547 % one or more full rows, since then there is opportunity to access the
4548 % pixels in-place (without a copy) if the image is in memory, or in a
4549 % memory-mapped file. The returned pointer must *never* be deallocated
4552 % Pixels accessed via the returned pointer represent a simple array of type
4553 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4554 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4555 % obtain the meta-content (of type void) corresponding to the region.
4556 % Once the Quantum (and/or Quantum) array has been updated, the
4557 % changes must be saved back to the underlying image using
4558 % SyncAuthenticPixels() or they may be lost.
4560 % The format of the QueueAuthenticPixels() method is:
4562 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4563 % const ssize_t y,const size_t columns,const size_t rows,
4564 % ExceptionInfo *exception)
4566 % A description of each parameter follows:
4568 % o image: the image.
4570 % o x,y,columns,rows: These values define the perimeter of a region of
4573 % o exception: return any errors or warnings in this structure.
4576 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4577 const ssize_t y,const size_t columns,const size_t rows,
4578 ExceptionInfo *exception)
4584 id = GetOpenMPThreadId();
4589 assert(image != (Image *) NULL);
4590 assert(image->signature == MagickSignature);
4591 assert(image->cache != (Cache) NULL);
4592 cache_info=(CacheInfo *) image->cache;
4593 assert(cache_info->signature == MagickSignature);
4594 if (cache_info->methods.queue_authentic_pixels_handler !=
4595 (QueueAuthenticPixelsHandler) NULL)
4597 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4598 columns,rows,exception);
4601 assert(id < (int) cache_info->number_threads);
4602 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4603 cache_info->nexus_info[id],exception);
4608 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4612 + 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 %
4616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4618 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4621 % The format of the ReadPixelCacheMetacontent() method is:
4623 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4624 % NexusInfo *nexus_info,ExceptionInfo *exception)
4626 % A description of each parameter follows:
4628 % o cache_info: the pixel cache.
4630 % o nexus_info: the cache nexus to read the metacontent.
4632 % o exception: return any errors or warnings in this structure.
4635 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4636 NexusInfo *nexus_info,ExceptionInfo *exception)
4649 register unsigned char
4655 if (cache_info->metacontent_extent == 0)
4656 return(MagickFalse);
4657 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4659 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4660 nexus_info->region.x;
4661 length=(MagickSizeType) nexus_info->region.width*
4662 cache_info->metacontent_extent;
4663 rows=nexus_info->region.height;
4665 q=(unsigned char *) nexus_info->metacontent;
4666 switch (cache_info->type)
4671 register unsigned char
4675 Read meta-content from memory.
4677 if ((cache_info->columns == nexus_info->region.width) &&
4678 (extent == (MagickSizeType) ((size_t) extent)))
4683 p=(unsigned char *) cache_info->metacontent+offset*
4684 cache_info->metacontent_extent;
4685 for (y=0; y < (ssize_t) rows; y++)
4687 (void) memcpy(q,p,(size_t) length);
4688 p+=cache_info->metacontent_extent*cache_info->columns;
4689 q+=cache_info->metacontent_extent*nexus_info->region.width;
4696 Read meta content from disk.
4698 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4700 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4701 cache_info->cache_filename);
4702 return(MagickFalse);
4704 if ((cache_info->columns == nexus_info->region.width) &&
4705 (extent <= MagickMaxBufferExtent))
4710 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4711 for (y=0; y < (ssize_t) rows; y++)
4713 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4714 cache_info->number_channels*sizeof(Quantum)+offset*
4715 cache_info->metacontent_extent,length,(unsigned char *) q);
4716 if ((MagickSizeType) count != length)
4718 offset+=cache_info->columns;
4719 q+=cache_info->metacontent_extent*nexus_info->region.width;
4721 if (y < (ssize_t) rows)
4723 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4724 cache_info->cache_filename);
4725 return(MagickFalse);
4732 if ((cache_info->debug != MagickFalse) &&
4733 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4734 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4735 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4736 nexus_info->region.width,(double) nexus_info->region.height,(double)
4737 nexus_info->region.x,(double) nexus_info->region.y);
4742 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4746 + R e a d P i x e l C a c h e P i x e l s %
4750 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4752 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4755 % The format of the ReadPixelCachePixels() method is:
4757 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4758 % NexusInfo *nexus_info,ExceptionInfo *exception)
4760 % A description of each parameter follows:
4762 % o cache_info: the pixel cache.
4764 % o nexus_info: the cache nexus to read the pixels.
4766 % o exception: return any errors or warnings in this structure.
4769 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4770 NexusInfo *nexus_info,ExceptionInfo *exception)
4789 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4791 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4792 nexus_info->region.x;
4793 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4795 rows=nexus_info->region.height;
4797 q=nexus_info->pixels;
4798 switch (cache_info->type)
4807 Read pixels from memory.
4809 if ((cache_info->columns == nexus_info->region.width) &&
4810 (extent == (MagickSizeType) ((size_t) extent)))
4815 p=cache_info->pixels+offset*cache_info->number_channels;
4816 for (y=0; y < (ssize_t) rows; y++)
4818 (void) memcpy(q,p,(size_t) length);
4819 p+=cache_info->number_channels*cache_info->columns;
4820 q+=cache_info->number_channels*nexus_info->region.width;
4827 Read pixels from disk.
4829 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4831 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4832 cache_info->cache_filename);
4833 return(MagickFalse);
4835 if ((cache_info->columns == nexus_info->region.width) &&
4836 (extent <= MagickMaxBufferExtent))
4841 for (y=0; y < (ssize_t) rows; y++)
4843 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4844 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4845 if ((MagickSizeType) count != length)
4847 offset+=cache_info->columns;
4848 q+=cache_info->number_channels*nexus_info->region.width;
4850 if (y < (ssize_t) rows)
4852 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4853 cache_info->cache_filename);
4854 return(MagickFalse);
4861 if ((cache_info->debug != MagickFalse) &&
4862 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4863 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4864 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4865 nexus_info->region.width,(double) nexus_info->region.height,(double)
4866 nexus_info->region.x,(double) nexus_info->region.y);
4871 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4875 + R e f e r e n c e P i x e l C a c h e %
4879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4881 % ReferencePixelCache() increments the reference count associated with the
4882 % pixel cache returning a pointer to the cache.
4884 % The format of the ReferencePixelCache method is:
4886 % Cache ReferencePixelCache(Cache cache_info)
4888 % A description of each parameter follows:
4890 % o cache_info: the pixel cache.
4893 MagickPrivate Cache ReferencePixelCache(Cache cache)
4898 assert(cache != (Cache *) NULL);
4899 cache_info=(CacheInfo *) cache;
4900 assert(cache_info->signature == MagickSignature);
4901 LockSemaphoreInfo(cache_info->semaphore);
4902 cache_info->reference_count++;
4903 UnlockSemaphoreInfo(cache_info->semaphore);
4908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4912 + S e t P i x e l C a c h e M e t h o d s %
4916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4918 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4920 % The format of the SetPixelCacheMethods() method is:
4922 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4924 % A description of each parameter follows:
4926 % o cache: the pixel cache.
4928 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4931 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4936 GetOneAuthenticPixelFromHandler
4937 get_one_authentic_pixel_from_handler;
4939 GetOneVirtualPixelFromHandler
4940 get_one_virtual_pixel_from_handler;
4943 Set cache pixel methods.
4945 assert(cache != (Cache) NULL);
4946 assert(cache_methods != (CacheMethods *) NULL);
4947 cache_info=(CacheInfo *) cache;
4948 assert(cache_info->signature == MagickSignature);
4949 if (cache_info->debug != MagickFalse)
4950 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4951 cache_info->filename);
4952 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4953 cache_info->methods.get_virtual_pixel_handler=
4954 cache_methods->get_virtual_pixel_handler;
4955 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4956 cache_info->methods.destroy_pixel_handler=
4957 cache_methods->destroy_pixel_handler;
4958 if (cache_methods->get_virtual_metacontent_from_handler !=
4959 (GetVirtualMetacontentFromHandler) NULL)
4960 cache_info->methods.get_virtual_metacontent_from_handler=
4961 cache_methods->get_virtual_metacontent_from_handler;
4962 if (cache_methods->get_authentic_pixels_handler !=
4963 (GetAuthenticPixelsHandler) NULL)
4964 cache_info->methods.get_authentic_pixels_handler=
4965 cache_methods->get_authentic_pixels_handler;
4966 if (cache_methods->queue_authentic_pixels_handler !=
4967 (QueueAuthenticPixelsHandler) NULL)
4968 cache_info->methods.queue_authentic_pixels_handler=
4969 cache_methods->queue_authentic_pixels_handler;
4970 if (cache_methods->sync_authentic_pixels_handler !=
4971 (SyncAuthenticPixelsHandler) NULL)
4972 cache_info->methods.sync_authentic_pixels_handler=
4973 cache_methods->sync_authentic_pixels_handler;
4974 if (cache_methods->get_authentic_pixels_from_handler !=
4975 (GetAuthenticPixelsFromHandler) NULL)
4976 cache_info->methods.get_authentic_pixels_from_handler=
4977 cache_methods->get_authentic_pixels_from_handler;
4978 if (cache_methods->get_authentic_metacontent_from_handler !=
4979 (GetAuthenticMetacontentFromHandler) NULL)
4980 cache_info->methods.get_authentic_metacontent_from_handler=
4981 cache_methods->get_authentic_metacontent_from_handler;
4982 get_one_virtual_pixel_from_handler=
4983 cache_info->methods.get_one_virtual_pixel_from_handler;
4984 if (get_one_virtual_pixel_from_handler !=
4985 (GetOneVirtualPixelFromHandler) NULL)
4986 cache_info->methods.get_one_virtual_pixel_from_handler=
4987 cache_methods->get_one_virtual_pixel_from_handler;
4988 get_one_authentic_pixel_from_handler=
4989 cache_methods->get_one_authentic_pixel_from_handler;
4990 if (get_one_authentic_pixel_from_handler !=
4991 (GetOneAuthenticPixelFromHandler) NULL)
4992 cache_info->methods.get_one_authentic_pixel_from_handler=
4993 cache_methods->get_one_authentic_pixel_from_handler;
4997 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5001 + S e t P i x e l C a c h e N e x u s P i x e l s %
5005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5007 % SetPixelCacheNexusPixels() defines the region of the cache for the
5008 % specified cache nexus.
5010 % The format of the SetPixelCacheNexusPixels() method is:
5012 % Quantum SetPixelCacheNexusPixels(const Image *image,
5013 % const RectangleInfo *region,NexusInfo *nexus_info,
5014 % ExceptionInfo *exception)
5016 % A description of each parameter follows:
5018 % o image: the image.
5020 % o region: A pointer to the RectangleInfo structure that defines the
5021 % region of this particular cache nexus.
5023 % o nexus_info: the cache nexus to set.
5025 % o exception: return any errors or warnings in this structure.
5029 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5030 NexusInfo *nexus_info,ExceptionInfo *exception)
5032 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5033 return(MagickFalse);
5034 nexus_info->mapped=MagickFalse;
5035 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
5036 nexus_info->length);
5037 if (nexus_info->cache == (Quantum *) NULL)
5039 nexus_info->mapped=MagickTrue;
5040 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
5041 nexus_info->length);
5043 if (nexus_info->cache == (Quantum *) NULL)
5045 (void) ThrowMagickException(exception,GetMagickModule(),
5046 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5047 cache_info->filename);
5048 return(MagickFalse);
5053 static Quantum *SetPixelCacheNexusPixels(const Image *image,
5054 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5066 cache_info=(CacheInfo *) image->cache;
5067 assert(cache_info->signature == MagickSignature);
5068 if (cache_info->type == UndefinedCache)
5069 return((Quantum *) NULL);
5070 nexus_info->region=(*region);
5071 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5072 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5078 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5079 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5080 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5081 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5082 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5083 ((nexus_info->region.width == cache_info->columns) ||
5084 ((nexus_info->region.width % cache_info->columns) == 0)))))
5090 Pixels are accessed directly from memory.
5092 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5093 nexus_info->region.x;
5094 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5096 nexus_info->metacontent=(void *) NULL;
5097 if (cache_info->metacontent_extent != 0)
5098 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5099 offset*cache_info->metacontent_extent;
5100 return(nexus_info->pixels);
5104 Pixels are stored in a cache region until they are synced to the cache.
5106 number_pixels=(MagickSizeType) nexus_info->region.width*
5107 nexus_info->region.height;
5108 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
5109 if (cache_info->metacontent_extent != 0)
5110 length+=number_pixels*cache_info->metacontent_extent;
5111 if (nexus_info->cache == (Quantum *) NULL)
5113 nexus_info->length=length;
5114 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5115 if (status == MagickFalse)
5117 nexus_info->length=0;
5118 return((Quantum *) NULL);
5122 if (nexus_info->length != length)
5124 RelinquishCacheNexusPixels(nexus_info);
5125 nexus_info->length=length;
5126 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5127 if (status == MagickFalse)
5129 nexus_info->length=0;
5130 return((Quantum *) NULL);
5133 nexus_info->pixels=nexus_info->cache;
5134 nexus_info->metacontent=(void *) NULL;
5135 if (cache_info->metacontent_extent != 0)
5136 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
5137 cache_info->number_channels);
5138 return(nexus_info->pixels);
5142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5146 % 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 %
5150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5152 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5153 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5154 % access that is outside the boundaries of the image cache.
5156 % The format of the SetPixelCacheVirtualMethod() method is:
5158 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5159 % const VirtualPixelMethod virtual_pixel_method)
5161 % A description of each parameter follows:
5163 % o image: the image.
5165 % o virtual_pixel_method: choose the type of virtual pixel.
5168 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5169 const VirtualPixelMethod virtual_pixel_method)
5177 assert(image != (Image *) NULL);
5178 assert(image->signature == MagickSignature);
5179 if (image->debug != MagickFalse)
5180 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5181 assert(image->cache != (Cache) NULL);
5182 cache_info=(CacheInfo *) image->cache;
5183 assert(cache_info->signature == MagickSignature);
5184 method=cache_info->virtual_pixel_method;
5185 cache_info->virtual_pixel_method=virtual_pixel_method;
5190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5194 + 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 %
5198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5200 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5201 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5202 % is synced, otherwise MagickFalse.
5204 % The format of the SyncAuthenticPixelCacheNexus() method is:
5206 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5207 % NexusInfo *nexus_info,ExceptionInfo *exception)
5209 % A description of each parameter follows:
5211 % o image: the image.
5213 % o nexus_info: the cache nexus to sync.
5215 % o exception: return any errors or warnings in this structure.
5218 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5219 NexusInfo *nexus_info,ExceptionInfo *exception)
5228 Transfer pixels to the cache.
5230 assert(image != (Image *) NULL);
5231 assert(image->signature == MagickSignature);
5232 if (image->cache == (Cache) NULL)
5233 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5234 cache_info=(CacheInfo *) image->cache;
5235 assert(cache_info->signature == MagickSignature);
5236 if (cache_info->type == UndefinedCache)
5237 return(MagickFalse);
5238 if ((image->clip_mask != (Image *) NULL) &&
5239 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5240 return(MagickFalse);
5241 if ((image->mask != (Image *) NULL) &&
5242 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5243 return(MagickFalse);
5244 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5246 assert(cache_info->signature == MagickSignature);
5247 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5248 if ((cache_info->metacontent_extent != 0) &&
5249 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5250 return(MagickFalse);
5255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5259 + S y n c A u t h e n t i c P i x e l C a c h e %
5263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5265 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5266 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5267 % otherwise MagickFalse.
5269 % The format of the SyncAuthenticPixelsCache() method is:
5271 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5272 % ExceptionInfo *exception)
5274 % A description of each parameter follows:
5276 % o image: the image.
5278 % o exception: return any errors or warnings in this structure.
5281 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5282 ExceptionInfo *exception)
5288 id = GetOpenMPThreadId();
5293 assert(image != (Image *) NULL);
5294 assert(image->signature == MagickSignature);
5295 assert(image->cache != (Cache) NULL);
5296 cache_info=(CacheInfo *) image->cache;
5297 assert(cache_info->signature == MagickSignature);
5298 assert(id < (int) cache_info->number_threads);
5299 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5309 % S y n c A u t h e n t i c P i x e l s %
5313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5315 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5316 % The method returns MagickTrue if the pixel region is flushed, otherwise
5319 % The format of the SyncAuthenticPixels() method is:
5321 % MagickBooleanType SyncAuthenticPixels(Image *image,
5322 % ExceptionInfo *exception)
5324 % A description of each parameter follows:
5326 % o image: the image.
5328 % o exception: return any errors or warnings in this structure.
5331 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5332 ExceptionInfo *exception)
5338 id = GetOpenMPThreadId();
5343 assert(image != (Image *) NULL);
5344 assert(image->signature == MagickSignature);
5345 assert(image->cache != (Cache) NULL);
5346 cache_info=(CacheInfo *) image->cache;
5347 assert(cache_info->signature == MagickSignature);
5348 if (cache_info->methods.sync_authentic_pixels_handler !=
5349 (SyncAuthenticPixelsHandler) NULL)
5351 status=cache_info->methods.sync_authentic_pixels_handler(image,
5355 assert(id < (int) cache_info->number_threads);
5356 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5366 + S y n c I m a g e P i x e l C a c h e %
5370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5372 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5373 % The method returns MagickTrue if the pixel region is flushed, otherwise
5376 % The format of the SyncImagePixelCache() method is:
5378 % MagickBooleanType SyncImagePixelCache(Image *image,
5379 % ExceptionInfo *exception)
5381 % A description of each parameter follows:
5383 % o image: the image.
5385 % o exception: return any errors or warnings in this structure.
5388 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5389 ExceptionInfo *exception)
5394 assert(image != (Image *) NULL);
5395 assert(exception != (ExceptionInfo *) NULL);
5396 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5397 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5405 + 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 %
5409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5411 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5412 % of the pixel cache.
5414 % The format of the WritePixelCacheMetacontent() method is:
5416 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5417 % NexusInfo *nexus_info,ExceptionInfo *exception)
5419 % A description of each parameter follows:
5421 % o cache_info: the pixel cache.
5423 % o nexus_info: the cache nexus to write the meta-content.
5425 % o exception: return any errors or warnings in this structure.
5428 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5429 NexusInfo *nexus_info,ExceptionInfo *exception)
5439 register const unsigned char
5448 if (cache_info->metacontent_extent == 0)
5449 return(MagickFalse);
5450 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5452 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5453 nexus_info->region.x;
5454 length=(MagickSizeType) nexus_info->region.width*
5455 cache_info->metacontent_extent;
5456 rows=nexus_info->region.height;
5457 extent=(MagickSizeType) length*rows;
5458 p=(unsigned char *) nexus_info->metacontent;
5459 switch (cache_info->type)
5464 register unsigned char
5468 Write associated pixels to memory.
5470 if ((cache_info->columns == nexus_info->region.width) &&
5471 (extent == (MagickSizeType) ((size_t) extent)))
5476 q=(unsigned char *) cache_info->metacontent+offset*
5477 cache_info->metacontent_extent;
5478 for (y=0; y < (ssize_t) rows; y++)
5480 (void) memcpy(q,p,(size_t) length);
5481 p+=nexus_info->region.width*cache_info->metacontent_extent;
5482 q+=cache_info->columns*cache_info->metacontent_extent;
5489 Write associated pixels to disk.
5491 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5493 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5494 cache_info->cache_filename);
5495 return(MagickFalse);
5497 if ((cache_info->columns == nexus_info->region.width) &&
5498 (extent <= MagickMaxBufferExtent))
5503 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5504 for (y=0; y < (ssize_t) rows; y++)
5506 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5507 cache_info->number_channels*sizeof(Quantum)+offset*
5508 cache_info->metacontent_extent,length,(const unsigned char *) p);
5509 if ((MagickSizeType) count != length)
5511 p+=nexus_info->region.width*cache_info->metacontent_extent;
5512 offset+=cache_info->columns;
5514 if (y < (ssize_t) rows)
5516 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5517 cache_info->cache_filename);
5518 return(MagickFalse);
5525 if ((cache_info->debug != MagickFalse) &&
5526 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5527 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5528 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5529 nexus_info->region.width,(double) nexus_info->region.height,(double)
5530 nexus_info->region.x,(double) nexus_info->region.y);
5535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5539 + W r i t e C a c h e P i x e l s %
5543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5545 % WritePixelCachePixels() writes image pixels to the specified region of the
5548 % The format of the WritePixelCachePixels() method is:
5550 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5551 % NexusInfo *nexus_info,ExceptionInfo *exception)
5553 % A description of each parameter follows:
5555 % o cache_info: the pixel cache.
5557 % o nexus_info: the cache nexus to write the pixels.
5559 % o exception: return any errors or warnings in this structure.
5562 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5563 NexusInfo *nexus_info,ExceptionInfo *exception)
5573 register const Quantum
5582 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5584 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5585 nexus_info->region.x;
5586 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5588 rows=nexus_info->region.height;
5590 p=nexus_info->pixels;
5591 switch (cache_info->type)
5600 Write pixels to memory.
5602 if ((cache_info->columns == nexus_info->region.width) &&
5603 (extent == (MagickSizeType) ((size_t) extent)))
5608 q=cache_info->pixels+offset*cache_info->number_channels;
5609 for (y=0; y < (ssize_t) rows; y++)
5611 (void) memcpy(q,p,(size_t) length);
5612 p+=nexus_info->region.width*cache_info->number_channels;
5613 q+=cache_info->columns*cache_info->number_channels;
5620 Write pixels to disk.
5622 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5624 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5625 cache_info->cache_filename);
5626 return(MagickFalse);
5628 if ((cache_info->columns == nexus_info->region.width) &&
5629 (extent <= MagickMaxBufferExtent))
5634 for (y=0; y < (ssize_t) rows; y++)
5636 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5637 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5639 if ((MagickSizeType) count != length)
5641 p+=nexus_info->region.width*cache_info->number_channels;
5642 offset+=cache_info->columns;
5644 if (y < (ssize_t) rows)
5646 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5647 cache_info->cache_filename);
5648 return(MagickFalse);
5655 if ((cache_info->debug != MagickFalse) &&
5656 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5657 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5658 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5659 nexus_info->region.width,(double) nexus_info->region.height,(double)
5660 nexus_info->region.x,(double) nexus_info->region.y);