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
428 Clip the image as defined by the clipping mask.
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,nexus_info->region.x,
443 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
444 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 (x=0; x < (ssize_t) number_pixels; x++)
456 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
458 if (GetPixelIntensity(image->clip_mask,r) > ((Quantum) QuantumRange/2))
459 for (i=0; i < (ssize_t) image->number_channels; i++)
467 channel=GetPixelChannelMapChannel(image,i);
468 traits=GetPixelChannelMapTraits(image,channel);
469 if (traits == UndefinedPixelTrait)
473 p+=GetPixelChannels(image);
474 q+=GetPixelChannels(image);
475 r+=GetPixelChannels(image->clip_mask);
477 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
478 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
479 if (x < (ssize_t) number_pixels)
485 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
489 + C l o n e P i x e l C a c h e %
493 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
495 % ClonePixelCache() clones a pixel cache.
497 % The format of the ClonePixelCache() method is:
499 % Cache ClonePixelCache(const Cache cache)
501 % A description of each parameter follows:
503 % o cache: the pixel cache.
506 MagickPrivate Cache ClonePixelCache(const Cache cache)
514 assert(cache != NULL);
515 cache_info=(const CacheInfo *) cache;
516 assert(cache_info->signature == MagickSignature);
517 if (cache_info->debug != MagickFalse)
518 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
519 cache_info->filename);
520 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
521 if (clone_info == (Cache) NULL)
522 return((Cache) NULL);
523 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
524 return((Cache ) clone_info);
528 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
532 + C l o n e P i x e l C a c h e P i x e l s %
536 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
537 % ClonePixelCachePixels() clones the source pixel cache to the destination
540 % The format of the ClonePixelCachePixels() method is:
542 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
543 % CacheInfo *source_info,ExceptionInfo *exception)
545 % A description of each parameter follows:
547 % o cache_info: the pixel cache.
549 % o source_info: the source pixel cache.
551 % o exception: return any errors or warnings in this structure.
555 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
561 LockSemaphoreInfo(cache_info->disk_semaphore);
562 if (cache_info->file != -1)
564 status=close(cache_info->file);
565 cache_info->file=(-1);
566 RelinquishMagickResource(FileResource,1);
568 UnlockSemaphoreInfo(cache_info->disk_semaphore);
569 return(status == -1 ? MagickFalse : MagickTrue);
572 static void LimitPixelCacheDescriptors(void)
579 Limit # of open file descriptors.
581 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
583 LockSemaphoreInfo(cache_semaphore);
584 if (cache_resources == (SplayTreeInfo *) NULL)
586 UnlockSemaphoreInfo(cache_semaphore);
589 ResetSplayTreeIterator(cache_resources);
590 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
591 while (p != (CacheInfo *) NULL)
593 if ((p->type == DiskCache) && (p->file != -1))
595 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
597 for (q=p; p != (CacheInfo *) NULL; )
599 if ((p->type == DiskCache) && (p->file != -1) &&
600 (p->timestamp < q->timestamp))
602 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
604 if (q != (CacheInfo *) NULL)
607 Close least recently used cache.
609 (void) close(q->file);
612 UnlockSemaphoreInfo(cache_semaphore);
615 static inline MagickSizeType MagickMax(const MagickSizeType x,
616 const MagickSizeType y)
623 static inline MagickSizeType MagickMin(const MagickSizeType x,
624 const MagickSizeType y)
631 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
638 Open pixel cache on disk.
640 LockSemaphoreInfo(cache_info->disk_semaphore);
641 if (cache_info->file != -1)
643 UnlockSemaphoreInfo(cache_info->disk_semaphore);
644 return(MagickTrue); /* cache already open */
646 LimitPixelCacheDescriptors();
647 if (*cache_info->cache_filename == '\0')
648 file=AcquireUniqueFileResource(cache_info->cache_filename);
654 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
659 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
660 O_BINARY | O_EXCL,S_MODE);
662 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
668 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
671 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
680 (void) AcquireMagickResource(FileResource,1);
681 cache_info->file=file;
682 cache_info->mode=mode;
683 cache_info->timestamp=time(0);
684 UnlockSemaphoreInfo(cache_info->disk_semaphore);
688 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
689 const MagickOffsetType offset,const MagickSizeType length,
690 unsigned char *restrict buffer)
692 register MagickOffsetType
698 cache_info->timestamp=time(0);
699 #if !defined(MAGICKCORE_HAVE_PREAD)
700 LockSemaphoreInfo(cache_info->disk_semaphore);
701 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
703 UnlockSemaphoreInfo(cache_info->disk_semaphore);
704 return((MagickOffsetType) -1);
708 for (i=0; i < (MagickOffsetType) length; i+=count)
710 #if !defined(MAGICKCORE_HAVE_PREAD)
711 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
712 (MagickSizeType) SSIZE_MAX));
714 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
715 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
726 #if !defined(MAGICKCORE_HAVE_PREAD)
727 UnlockSemaphoreInfo(cache_info->disk_semaphore);
732 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
733 const MagickOffsetType offset,const MagickSizeType length,
734 const unsigned char *restrict buffer)
736 register MagickOffsetType
742 cache_info->timestamp=time(0);
743 #if !defined(MAGICKCORE_HAVE_PWRITE)
744 LockSemaphoreInfo(cache_info->disk_semaphore);
745 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
747 UnlockSemaphoreInfo(cache_info->disk_semaphore);
748 return((MagickOffsetType) -1);
752 for (i=0; i < (MagickOffsetType) length; i+=count)
754 #if !defined(MAGICKCORE_HAVE_PWRITE)
755 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
756 (MagickSizeType) SSIZE_MAX));
758 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
759 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
770 #if !defined(MAGICKCORE_HAVE_PWRITE)
771 UnlockSemaphoreInfo(cache_info->disk_semaphore);
776 static MagickBooleanType DiskToDiskPixelCacheClone(CacheInfo *clone_info,
777 CacheInfo *cache_info,ExceptionInfo *exception)
782 register MagickOffsetType
792 Clone pixel cache (both caches on disk).
794 if (cache_info->debug != MagickFalse)
795 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
796 blob=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
798 if (blob == (unsigned char *) NULL)
800 (void) ThrowMagickException(exception,GetMagickModule(),
801 ResourceLimitError,"MemoryAllocationFailed","`%s'",
802 cache_info->filename);
805 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
807 blob=(unsigned char *) RelinquishMagickMemory(blob);
808 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
809 cache_info->cache_filename);
812 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
814 (void) ClosePixelCacheOnDisk(cache_info);
815 blob=(unsigned char *) RelinquishMagickMemory(blob);
816 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
817 clone_info->cache_filename);
821 for (i=0; i < (MagickOffsetType) cache_info->length; i+=count)
823 count=ReadPixelCacheRegion(cache_info,cache_info->offset+i,
824 MagickMin(cache_info->length-i,(MagickSizeType) MagickMaxBufferExtent),
828 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
829 cache_info->cache_filename);
832 length=(size_t) count;
833 count=WritePixelCacheRegion(clone_info,clone_info->offset+i,length,blob);
834 if ((MagickSizeType) count != length)
836 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
837 clone_info->cache_filename);
841 (void) ClosePixelCacheOnDisk(clone_info);
842 (void) ClosePixelCacheOnDisk(cache_info);
843 blob=(unsigned char *) RelinquishMagickMemory(blob);
844 if (i < (MagickOffsetType) cache_info->length)
849 static MagickBooleanType PixelCacheCloneOptimized(CacheInfo *clone_info,
850 CacheInfo *cache_info,ExceptionInfo *exception)
855 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
858 Clone pixel cache (both caches in memory).
860 if (cache_info->debug != MagickFalse)
861 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
862 (void) memcpy(clone_info->pixels,cache_info->pixels,(size_t)
866 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
869 Clone pixel cache (one cache on disk, one in memory).
871 if (cache_info->debug != MagickFalse)
872 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
873 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
875 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
876 cache_info->cache_filename);
879 count=ReadPixelCacheRegion(cache_info,cache_info->offset,
880 cache_info->length,(unsigned char *) clone_info->pixels);
881 (void) ClosePixelCacheOnDisk(cache_info);
882 if ((MagickSizeType) count != cache_info->length)
884 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
885 cache_info->cache_filename);
890 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
893 Clone pixel cache (one cache on disk, one in memory).
895 if (clone_info->debug != MagickFalse)
896 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
897 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
899 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
900 clone_info->cache_filename);
903 count=WritePixelCacheRegion(clone_info,clone_info->offset,
904 clone_info->length,(unsigned char *) cache_info->pixels);
905 (void) ClosePixelCacheOnDisk(clone_info);
906 if ((MagickSizeType) count != clone_info->length)
908 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
909 clone_info->cache_filename);
915 Clone pixel cache (both caches on disk).
917 return(DiskToDiskPixelCacheClone(clone_info,cache_info,exception));
920 static MagickBooleanType PixelCacheCloneUnoptimized(CacheInfo *clone_info,
921 CacheInfo *cache_info,ExceptionInfo *exception)
934 register unsigned char
947 Clone pixel cache (unoptimized).
949 if (cache_info->debug != MagickFalse)
951 if ((cache_info->type != DiskCache) && (clone_info->type != DiskCache))
952 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
954 if ((clone_info->type != DiskCache) && (cache_info->type == DiskCache))
955 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
957 if ((clone_info->type == DiskCache) && (cache_info->type != DiskCache))
958 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
960 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
962 length=(size_t) MagickMax(MagickMax(cache_info->number_channels,
963 clone_info->number_channels)*sizeof(Quantum),MagickMax(
964 cache_info->metacontent_extent,clone_info->metacontent_extent));
965 blob=(unsigned char *) AcquireQuantumMemory(length,sizeof(*blob));
966 if (blob == (unsigned char *) NULL)
968 (void) ThrowMagickException(exception,GetMagickModule(),
969 ResourceLimitError,"MemoryAllocationFailed","`%s'",
970 cache_info->filename);
973 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
976 if (cache_info->type == DiskCache)
978 if (OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse)
980 blob=(unsigned char *) RelinquishMagickMemory(blob);
981 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
982 cache_info->cache_filename);
985 cache_offset=cache_info->offset;
987 if (clone_info->type == DiskCache)
989 if (OpenPixelCacheOnDisk(clone_info,WriteMode) == MagickFalse)
991 blob=(unsigned char *) RelinquishMagickMemory(blob);
992 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
993 clone_info->cache_filename);
996 clone_offset=clone_info->offset;
999 Clone pixel channels.
1003 for (y=0; y < (ssize_t) cache_info->rows; y++)
1005 for (x=0; x < (ssize_t) cache_info->columns; x++)
1011 Read a set of pixel channels.
1013 length=cache_info->number_channels*sizeof(Quantum);
1014 if (cache_info->type != DiskCache)
1015 p=(unsigned char *) cache_info->pixels+cache_offset;
1018 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
1019 if ((MagickSizeType) count != length)
1025 cache_offset+=length;
1026 if ((y < (ssize_t) clone_info->rows) &&
1027 (x < (ssize_t) clone_info->columns))
1028 for (i=0; i < (ssize_t) clone_info->number_channels; i++)
1040 Write a set of pixel channels.
1042 channel=clone_info->channel_map[i].channel;
1043 traits=cache_info->channel_map[channel].traits;
1044 if (traits == UndefinedPixelTrait)
1046 clone_offset+=sizeof(Quantum);
1049 offset=cache_info->channel_map[channel].offset;
1050 if (clone_info->type != DiskCache)
1051 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,p+
1052 offset*sizeof(Quantum),sizeof(Quantum));
1055 count=WritePixelCacheRegion(clone_info,clone_offset,
1056 sizeof(Quantum),p+offset*sizeof(Quantum));
1057 if ((MagickSizeType) count != sizeof(Quantum))
1063 clone_offset+=sizeof(Quantum);
1066 length=clone_info->number_channels*sizeof(Quantum);
1067 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1068 for ( ; x < (ssize_t) clone_info->columns; x++)
1071 Set remaining columns as undefined.
1073 if (clone_info->type != DiskCache)
1074 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1078 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1079 if ((MagickSizeType) count != length)
1085 clone_offset+=length;
1088 length=clone_info->number_channels*sizeof(Quantum);
1089 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1090 for ( ; y < (ssize_t) clone_info->rows; y++)
1093 Set remaining rows as undefined.
1095 for (x=0; x < (ssize_t) clone_info->columns; x++)
1097 if (clone_info->type != DiskCache)
1098 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,blob,
1102 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1103 if ((MagickSizeType) count != length)
1109 clone_offset+=length;
1112 if ((cache_info->metacontent_extent != 0) ||
1113 (clone_info->metacontent_extent != 0))
1118 for (y=0; y < (ssize_t) cache_info->rows; y++)
1120 for (x=0; x < (ssize_t) cache_info->columns; x++)
1123 Read a set of metacontent.
1125 length=cache_info->metacontent_extent;
1126 if (cache_info->type != DiskCache)
1127 p=(unsigned char *) cache_info->pixels+cache_offset;
1130 count=ReadPixelCacheRegion(cache_info,cache_offset,length,p);
1131 if ((MagickSizeType) count != length)
1137 cache_offset+=length;
1138 if ((y < (ssize_t) clone_info->rows) &&
1139 (x < (ssize_t) clone_info->columns))
1142 Write a set of metacontent.
1144 length=clone_info->metacontent_extent;
1145 if (clone_info->type != DiskCache)
1146 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1150 count=WritePixelCacheRegion(clone_info,clone_offset,length,p);
1151 if ((MagickSizeType) count != length)
1157 clone_offset+=length;
1160 length=clone_info->metacontent_extent;
1161 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1162 for ( ; x < (ssize_t) clone_info->columns; x++)
1165 Set remaining columns as undefined.
1167 if (clone_info->type != DiskCache)
1168 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1172 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1173 if ((MagickSizeType) count != length)
1179 clone_offset+=length;
1182 length=clone_info->metacontent_extent;
1183 (void) ResetMagickMemory(blob,0,length*sizeof(*blob));
1184 for ( ; y < (ssize_t) clone_info->rows; y++)
1187 Set remaining rows as undefined.
1189 for (x=0; x < (ssize_t) clone_info->columns; x++)
1191 if (clone_info->type != DiskCache)
1192 (void) memcpy((unsigned char *) clone_info->pixels+clone_offset,
1196 count=WritePixelCacheRegion(clone_info,clone_offset,length,blob);
1197 if ((MagickSizeType) count != length)
1203 clone_offset+=length;
1207 if (clone_info->type == DiskCache)
1208 (void) ClosePixelCacheOnDisk(clone_info);
1209 if (cache_info->type == DiskCache)
1210 (void) ClosePixelCacheOnDisk(cache_info);
1211 blob=(unsigned char *) RelinquishMagickMemory(blob);
1215 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1216 CacheInfo *cache_info,ExceptionInfo *exception)
1222 if (cache_info->type == PingCache)
1224 p=cache_info->channel_map;
1225 q=clone_info->channel_map;
1226 if ((cache_info->columns == clone_info->columns) &&
1227 (cache_info->rows == clone_info->rows) &&
1228 (cache_info->number_channels == clone_info->number_channels) &&
1229 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
1230 (cache_info->metacontent_extent == clone_info->metacontent_extent))
1231 return(PixelCacheCloneOptimized(clone_info,cache_info,exception));
1232 return(PixelCacheCloneUnoptimized(clone_info,cache_info,exception));
1236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1240 + C l o n e P i x e l C a c h e M e t h o d s %
1244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1246 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1249 % The format of the ClonePixelCacheMethods() method is:
1251 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1253 % A description of each parameter follows:
1255 % o clone: Specifies a pointer to a Cache structure.
1257 % o cache: the pixel cache.
1260 MagickPrivate void ClonePixelCacheMethods(Cache clone,const Cache cache)
1266 assert(clone != (Cache) NULL);
1267 source_info=(CacheInfo *) clone;
1268 assert(source_info->signature == MagickSignature);
1269 if (source_info->debug != MagickFalse)
1270 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1271 source_info->filename);
1272 assert(cache != (Cache) NULL);
1273 cache_info=(CacheInfo *) cache;
1274 assert(cache_info->signature == MagickSignature);
1275 source_info->methods=cache_info->methods;
1279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1283 + D e s t r o y I m a g e P i x e l C a c h e %
1287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1289 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1291 % The format of the DestroyImagePixelCache() method is:
1293 % void DestroyImagePixelCache(Image *image)
1295 % A description of each parameter follows:
1297 % o image: the image.
1300 static void DestroyImagePixelCache(Image *image)
1302 assert(image != (Image *) NULL);
1303 assert(image->signature == MagickSignature);
1304 if (image->debug != MagickFalse)
1305 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1306 if (image->cache == (void *) NULL)
1308 image->cache=DestroyPixelCache(image->cache);
1312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1316 + D e s t r o y I m a g e P i x e l s %
1320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1322 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1324 % The format of the DestroyImagePixels() method is:
1326 % void DestroyImagePixels(Image *image)
1328 % A description of each parameter follows:
1330 % o image: the image.
1333 MagickExport void DestroyImagePixels(Image *image)
1338 assert(image != (const Image *) NULL);
1339 assert(image->signature == MagickSignature);
1340 if (image->debug != MagickFalse)
1341 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1342 assert(image->cache != (Cache) NULL);
1343 cache_info=(CacheInfo *) image->cache;
1344 assert(cache_info->signature == MagickSignature);
1345 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1347 cache_info->methods.destroy_pixel_handler(image);
1350 image->cache=DestroyPixelCache(image->cache);
1354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1358 + D e s t r o y P i x e l C a c h e %
1362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1364 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1366 % The format of the DestroyPixelCache() method is:
1368 % Cache DestroyPixelCache(Cache cache)
1370 % A description of each parameter follows:
1372 % o cache: the pixel cache.
1376 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1378 switch (cache_info->type)
1382 if (cache_info->mapped == MagickFalse)
1383 cache_info->pixels=(Quantum *) RelinquishMagickMemory(
1384 cache_info->pixels);
1386 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,
1387 (size_t) cache_info->length);
1388 RelinquishMagickResource(MemoryResource,cache_info->length);
1393 cache_info->pixels=(Quantum *) UnmapBlob(cache_info->pixels,(size_t)
1394 cache_info->length);
1395 RelinquishMagickResource(MapResource,cache_info->length);
1399 if (cache_info->file != -1)
1400 (void) ClosePixelCacheOnDisk(cache_info);
1401 RelinquishMagickResource(DiskResource,cache_info->length);
1407 cache_info->type=UndefinedCache;
1408 cache_info->mapped=MagickFalse;
1409 cache_info->metacontent=(void *) NULL;
1412 MagickPrivate Cache DestroyPixelCache(Cache cache)
1417 assert(cache != (Cache) NULL);
1418 cache_info=(CacheInfo *) cache;
1419 assert(cache_info->signature == MagickSignature);
1420 if (cache_info->debug != MagickFalse)
1421 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1422 cache_info->filename);
1423 LockSemaphoreInfo(cache_info->semaphore);
1424 cache_info->reference_count--;
1425 if (cache_info->reference_count != 0)
1427 UnlockSemaphoreInfo(cache_info->semaphore);
1428 return((Cache) NULL);
1430 UnlockSemaphoreInfo(cache_info->semaphore);
1431 if (cache_resources != (SplayTreeInfo *) NULL)
1432 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1433 if (cache_info->debug != MagickFalse)
1436 message[MaxTextExtent];
1438 (void) FormatLocaleString(message,MaxTextExtent,"destroy %s",
1439 cache_info->filename);
1440 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1442 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1443 (cache_info->type != DiskCache)))
1444 RelinquishPixelCachePixels(cache_info);
1447 RelinquishPixelCachePixels(cache_info);
1448 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1450 *cache_info->cache_filename='\0';
1451 if (cache_info->nexus_info != (NexusInfo **) NULL)
1452 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1453 cache_info->number_threads);
1454 if (cache_info->random_info != (RandomInfo *) NULL)
1455 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1456 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1457 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1458 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1459 DestroySemaphoreInfo(&cache_info->semaphore);
1460 cache_info->signature=(~MagickSignature);
1461 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1471 + D e s t r o y P i x e l C a c h e N e x u s %
1475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1477 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1479 % The format of the DestroyPixelCacheNexus() method is:
1481 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1482 % const size_t number_threads)
1484 % A description of each parameter follows:
1486 % o nexus_info: the nexus to destroy.
1488 % o number_threads: the number of nexus threads.
1492 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1494 if (nexus_info->mapped == MagickFalse)
1495 (void) RelinquishMagickMemory(nexus_info->cache);
1497 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1498 nexus_info->cache=(Quantum *) NULL;
1499 nexus_info->pixels=(Quantum *) NULL;
1500 nexus_info->metacontent=(void *) NULL;
1501 nexus_info->length=0;
1502 nexus_info->mapped=MagickFalse;
1505 MagickPrivate NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1506 const size_t number_threads)
1511 assert(nexus_info != (NexusInfo **) NULL);
1512 for (i=0; i < (ssize_t) number_threads; i++)
1514 if (nexus_info[i]->cache != (Quantum *) NULL)
1515 RelinquishCacheNexusPixels(nexus_info[i]);
1516 nexus_info[i]->signature=(~MagickSignature);
1517 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1519 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1528 % G e t A u t h e n t i c M e t a c o n t e n t %
1532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1534 % GetAuthenticMetacontent() returns the authentic metacontent corresponding
1535 % with the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
1536 % returned if the associated pixels are not available.
1538 % The format of the GetAuthenticMetacontent() method is:
1540 % void *GetAuthenticMetacontent(const Image *image)
1542 % A description of each parameter follows:
1544 % o image: the image.
1547 MagickExport void *GetAuthenticMetacontent(const Image *image)
1553 id = GetOpenMPThreadId();
1558 assert(image != (const Image *) NULL);
1559 assert(image->signature == MagickSignature);
1560 assert(image->cache != (Cache) NULL);
1561 cache_info=(CacheInfo *) image->cache;
1562 assert(cache_info->signature == MagickSignature);
1563 if (cache_info->methods.get_authentic_metacontent_from_handler !=
1564 (GetAuthenticMetacontentFromHandler) NULL)
1566 metacontent=cache_info->methods.
1567 get_authentic_metacontent_from_handler(image);
1568 return(metacontent);
1570 assert(id < (int) cache_info->number_threads);
1571 metacontent=GetPixelCacheNexusMetacontent(cache_info,
1572 cache_info->nexus_info[id]);
1573 return(metacontent);
1577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1581 + 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 %
1585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587 % GetAuthenticMetacontentFromCache() returns the meta-content corresponding
1588 % with the last call to QueueAuthenticPixelsCache() or
1589 % GetAuthenticPixelsCache().
1591 % The format of the GetAuthenticMetacontentFromCache() method is:
1593 % void *GetAuthenticMetacontentFromCache(const Image *image)
1595 % A description of each parameter follows:
1597 % o image: the image.
1600 static void *GetAuthenticMetacontentFromCache(const Image *image)
1606 id = GetOpenMPThreadId();
1611 assert(image != (const Image *) NULL);
1612 assert(image->signature == MagickSignature);
1613 assert(image->cache != (Cache) NULL);
1614 cache_info=(CacheInfo *) image->cache;
1615 assert(cache_info->signature == MagickSignature);
1616 assert(id < (int) cache_info->number_threads);
1617 metacontent=GetPixelCacheNexusMetacontent(image->cache,
1618 cache_info->nexus_info[id]);
1619 return(metacontent);
1623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1627 + 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 %
1631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1634 % disk pixel cache as defined by the geometry parameters. A pointer to the
1635 % pixels is returned if the pixels are transferred, otherwise a NULL is
1638 % The format of the GetAuthenticPixelCacheNexus() method is:
1640 % Quantum *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1641 % const ssize_t y,const size_t columns,const size_t rows,
1642 % NexusInfo *nexus_info,ExceptionInfo *exception)
1644 % A description of each parameter follows:
1646 % o image: the image.
1648 % o x,y,columns,rows: These values define the perimeter of a region of
1651 % o nexus_info: the cache nexus to return.
1653 % o exception: return any errors or warnings in this structure.
1657 static inline MagickBooleanType IsPixelAuthentic(const CacheInfo *cache_info,
1658 NexusInfo *nexus_info)
1666 if (cache_info->type == PingCache)
1668 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1669 nexus_info->region.x;
1670 status=nexus_info->pixels == (cache_info->pixels+offset*
1671 cache_info->number_channels) ? MagickTrue : MagickFalse;
1675 MagickPrivate Quantum *GetAuthenticPixelCacheNexus(Image *image,
1676 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1677 NexusInfo *nexus_info,ExceptionInfo *exception)
1686 Transfer pixels from the cache.
1688 assert(image != (Image *) NULL);
1689 assert(image->signature == MagickSignature);
1690 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickTrue,nexus_info,exception);
1691 if (q == (Quantum *) NULL)
1692 return((Quantum *) NULL);
1693 cache_info=(CacheInfo *) image->cache;
1694 assert(cache_info->signature == MagickSignature);
1695 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
1697 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1698 return((Quantum *) NULL);
1699 if (cache_info->metacontent_extent != 0)
1700 if (ReadPixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse)
1701 return((Quantum *) NULL);
1706 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1710 + 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 %
1714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1716 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1717 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1719 % The format of the GetAuthenticPixelsFromCache() method is:
1721 % Quantum *GetAuthenticPixelsFromCache(const Image image)
1723 % A description of each parameter follows:
1725 % o image: the image.
1728 static Quantum *GetAuthenticPixelsFromCache(const Image *image)
1734 id = GetOpenMPThreadId();
1736 assert(image != (const Image *) NULL);
1737 assert(image->signature == MagickSignature);
1738 assert(image->cache != (Cache) NULL);
1739 cache_info=(CacheInfo *) image->cache;
1740 assert(cache_info->signature == MagickSignature);
1741 assert(id < (int) cache_info->number_threads);
1742 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1750 % G e t A u t h e n t i c P i x e l Q u e u e %
1754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1756 % GetAuthenticPixelQueue() returns the authentic pixels associated
1757 % corresponding with the last call to QueueAuthenticPixels() or
1758 % GetAuthenticPixels().
1760 % The format of the GetAuthenticPixelQueue() method is:
1762 % Quantum *GetAuthenticPixelQueue(const Image image)
1764 % A description of each parameter follows:
1766 % o image: the image.
1769 MagickExport Quantum *GetAuthenticPixelQueue(const Image *image)
1775 id = GetOpenMPThreadId();
1777 assert(image != (const Image *) NULL);
1778 assert(image->signature == MagickSignature);
1779 assert(image->cache != (Cache) NULL);
1780 cache_info=(CacheInfo *) image->cache;
1781 assert(cache_info->signature == MagickSignature);
1782 if (cache_info->methods.get_authentic_pixels_from_handler !=
1783 (GetAuthenticPixelsFromHandler) NULL)
1784 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1785 assert(id < (int) cache_info->number_threads);
1786 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1794 % G e t A u t h e n t i c P i x e l s %
1797 % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1799 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1800 % region is successfully accessed, a pointer to a Quantum array
1801 % representing the region is returned, otherwise NULL is returned.
1803 % The returned pointer may point to a temporary working copy of the pixels
1804 % or it may point to the original pixels in memory. Performance is maximized
1805 % if the selected region is part of one row, or one or more full rows, since
1806 % then there is opportunity to access the pixels in-place (without a copy)
1807 % if the image is in memory, or in a memory-mapped file. The returned pointer
1808 % must *never* be deallocated by the user.
1810 % Pixels accessed via the returned pointer represent a simple array of type
1811 % Quantum. If the image has corresponding metacontent,call
1812 % GetAuthenticMetacontent() after invoking GetAuthenticPixels() to obtain the
1813 % meta-content corresponding to the region. Once the Quantum array has
1814 % been updated, the changes must be saved back to the underlying image using
1815 % SyncAuthenticPixels() or they may be lost.
1817 % The format of the GetAuthenticPixels() method is:
1819 % Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1820 % const ssize_t y,const size_t columns,const size_t rows,
1821 % ExceptionInfo *exception)
1823 % A description of each parameter follows:
1825 % o image: the image.
1827 % o x,y,columns,rows: These values define the perimeter of a region of
1830 % o exception: return any errors or warnings in this structure.
1833 MagickExport Quantum *GetAuthenticPixels(Image *image,const ssize_t x,
1834 const ssize_t y,const size_t columns,const size_t rows,
1835 ExceptionInfo *exception)
1841 id = GetOpenMPThreadId();
1846 assert(image != (Image *) NULL);
1847 assert(image->signature == MagickSignature);
1848 assert(image->cache != (Cache) NULL);
1849 cache_info=(CacheInfo *) image->cache;
1850 assert(cache_info->signature == MagickSignature);
1851 if (cache_info->methods.get_authentic_pixels_handler !=
1852 (GetAuthenticPixelsHandler) NULL)
1854 q=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,rows,
1858 assert(id < (int) cache_info->number_threads);
1859 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1860 cache_info->nexus_info[id],exception);
1865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1869 + G e t A u t h e n t i c P i x e l s C a c h e %
1873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1875 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1876 % as defined by the geometry parameters. A pointer to the pixels is returned
1877 % if the pixels are transferred, otherwise a NULL is returned.
1879 % The format of the GetAuthenticPixelsCache() method is:
1881 % Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1882 % const ssize_t y,const size_t columns,const size_t rows,
1883 % ExceptionInfo *exception)
1885 % A description of each parameter follows:
1887 % o image: the image.
1889 % o x,y,columns,rows: These values define the perimeter of a region of
1892 % o exception: return any errors or warnings in this structure.
1895 static Quantum *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1896 const ssize_t y,const size_t columns,const size_t rows,
1897 ExceptionInfo *exception)
1903 id = GetOpenMPThreadId();
1908 assert(image != (const Image *) NULL);
1909 assert(image->signature == MagickSignature);
1910 assert(image->cache != (Cache) NULL);
1911 cache_info=(CacheInfo *) image->cache;
1912 if (cache_info == (Cache) NULL)
1913 return((Quantum *) NULL);
1914 assert(cache_info->signature == MagickSignature);
1915 assert(id < (int) cache_info->number_threads);
1916 q=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1917 cache_info->nexus_info[id],exception);
1922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1926 + G e t I m a g e E x t e n t %
1930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1932 % GetImageExtent() returns the extent of the pixels associated corresponding
1933 % with the last call to QueueAuthenticPixels() or GetAuthenticPixels().
1935 % The format of the GetImageExtent() method is:
1937 % MagickSizeType GetImageExtent(const Image *image)
1939 % A description of each parameter follows:
1941 % o image: the image.
1944 MagickExport MagickSizeType GetImageExtent(const Image *image)
1950 id = GetOpenMPThreadId();
1952 assert(image != (Image *) NULL);
1953 assert(image->signature == MagickSignature);
1954 if (image->debug != MagickFalse)
1955 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1956 assert(image->cache != (Cache) NULL);
1957 cache_info=(CacheInfo *) image->cache;
1958 assert(cache_info->signature == MagickSignature);
1959 assert(id < (int) cache_info->number_threads);
1960 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1968 + G e t I m a g e P i x e l C a c h e %
1972 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1974 % GetImagePixelCache() ensures that there is only a single reference to the
1975 % pixel cache to be modified, updating the provided cache pointer to point to
1976 % a clone of the original pixel cache if necessary.
1978 % The format of the GetImagePixelCache method is:
1980 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
1981 % ExceptionInfo *exception)
1983 % A description of each parameter follows:
1985 % o image: the image.
1987 % o clone: any value other than MagickFalse clones the cache pixels.
1989 % o exception: return any errors or warnings in this structure.
1993 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2003 Does the image match the pixel cache morphology?
2005 cache_info=(CacheInfo *) image->cache;
2006 p=image->channel_map;
2007 q=cache_info->channel_map;
2008 if ((image->storage_class != cache_info->storage_class) ||
2009 (image->colorspace != cache_info->colorspace) ||
2010 (image->matte != cache_info->matte) ||
2011 (image->columns != cache_info->columns) ||
2012 (image->rows != cache_info->rows) ||
2013 (image->number_channels != cache_info->number_channels) ||
2014 (memcmp(p,q,image->number_channels*sizeof(*p)) != 0) ||
2015 (image->metacontent_extent != cache_info->metacontent_extent) ||
2016 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2017 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2018 return(MagickFalse);
2022 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2023 ExceptionInfo *exception)
2032 static MagickSizeType
2038 cache_timestamp = 0;
2041 LockSemaphoreInfo(image->semaphore);
2042 if (cpu_throttle == 0)
2048 Set CPU throttle in milleseconds.
2050 cpu_throttle=MagickResourceInfinity;
2051 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2052 if (limit == (char *) NULL)
2053 limit=GetPolicyValue("throttle");
2054 if (limit != (char *) NULL)
2056 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2057 limit=DestroyString(limit);
2060 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2061 MagickDelay(cpu_throttle);
2062 if (time_limit == 0)
2065 Set the exire time in seconds.
2067 time_limit=GetMagickResourceLimit(TimeResource);
2068 cache_timestamp=time((time_t *) NULL);
2070 if ((time_limit != MagickResourceInfinity) &&
2071 ((MagickSizeType) (time((time_t *) NULL)-cache_timestamp) >= time_limit))
2072 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2073 assert(image->cache != (Cache) NULL);
2074 cache_info=(CacheInfo *) image->cache;
2075 destroy=MagickFalse;
2076 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2078 LockSemaphoreInfo(cache_info->semaphore);
2079 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2090 clone_image=(*image);
2091 clone_image.semaphore=AllocateSemaphoreInfo();
2092 clone_image.reference_count=1;
2093 clone_image.cache=ClonePixelCache(cache_info);
2094 clone_info=(CacheInfo *) clone_image.cache;
2095 status=OpenPixelCache(&clone_image,IOMode,exception);
2096 if (status != MagickFalse)
2098 if (clone != MagickFalse)
2099 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2100 if (status != MagickFalse)
2102 if (cache_info->mode == ReadMode)
2103 cache_info->nexus_info=(NexusInfo **) NULL;
2105 image->cache=clone_image.cache;
2108 DestroySemaphoreInfo(&clone_image.semaphore);
2110 UnlockSemaphoreInfo(cache_info->semaphore);
2112 if (destroy != MagickFalse)
2113 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2114 if (status != MagickFalse)
2117 Ensure the image matches the pixel cache morphology.
2119 image->taint=MagickTrue;
2120 image->type=UndefinedType;
2121 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2122 status=OpenPixelCache(image,IOMode,exception);
2124 UnlockSemaphoreInfo(image->semaphore);
2125 if (status == MagickFalse)
2126 return((Cache) NULL);
2127 return(image->cache);
2131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2135 % G e t O n e A u t h e n t i c P i x e l %
2139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2141 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2142 % location. The image background color is returned if an error occurs.
2144 % The format of the GetOneAuthenticPixel() method is:
2146 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2147 % const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2149 % A description of each parameter follows:
2151 % o image: the image.
2153 % o x,y: These values define the location of the pixel to return.
2155 % o pixel: return a pixel at the specified (x,y) location.
2157 % o exception: return any errors or warnings in this structure.
2160 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2161 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2172 assert(image != (Image *) NULL);
2173 assert(image->signature == MagickSignature);
2174 assert(image->cache != (Cache) NULL);
2175 cache_info=(CacheInfo *) image->cache;
2176 assert(cache_info->signature == MagickSignature);
2177 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2178 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2179 (GetOneAuthenticPixelFromHandler) NULL)
2180 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2182 q=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2183 if (q == (Quantum *) NULL)
2185 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2186 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2187 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2188 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2189 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2190 return(MagickFalse);
2192 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2197 channel=GetPixelChannelMapChannel(image,i);
2198 pixel[channel]=q[i];
2204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2208 + 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 %
2212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2214 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2215 % location. The image background color is returned if an error occurs.
2217 % The format of the GetOneAuthenticPixelFromCache() method is:
2219 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2220 % const ssize_t x,const ssize_t y,Quantum *pixel,
2221 % ExceptionInfo *exception)
2223 % A description of each parameter follows:
2225 % o image: the image.
2227 % o x,y: These values define the location of the pixel to return.
2229 % o pixel: return a pixel at the specified (x,y) location.
2231 % o exception: return any errors or warnings in this structure.
2234 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2235 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2241 id = GetOpenMPThreadId();
2249 assert(image != (const Image *) NULL);
2250 assert(image->signature == MagickSignature);
2251 assert(image->cache != (Cache) NULL);
2252 cache_info=(CacheInfo *) image->cache;
2253 assert(cache_info->signature == MagickSignature);
2254 assert(id < (int) cache_info->number_threads);
2255 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2256 q=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,cache_info->nexus_info[id],
2258 if (q == (Quantum *) NULL)
2260 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2261 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2262 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2263 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2264 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2265 return(MagickFalse);
2267 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2272 channel=GetPixelChannelMapChannel(image,i);
2273 pixel[channel]=q[i];
2279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2283 % G e t O n e V i r t u a l P i x e l %
2287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2289 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2290 % (x,y) location. The image background color is returned if an error occurs.
2291 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2293 % The format of the GetOneVirtualPixel() method is:
2295 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2296 % const ssize_t y,Quantum *pixel,ExceptionInfo exception)
2298 % A description of each parameter follows:
2300 % o image: the image.
2302 % o x,y: These values define the location of the pixel to return.
2304 % o pixel: return a pixel at the specified (x,y) location.
2306 % o exception: return any errors or warnings in this structure.
2309 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2310 const ssize_t x,const ssize_t y,Quantum *pixel,ExceptionInfo *exception)
2316 id = GetOpenMPThreadId();
2324 assert(image != (const Image *) NULL);
2325 assert(image->signature == MagickSignature);
2326 assert(image->cache != (Cache) NULL);
2327 cache_info=(CacheInfo *) image->cache;
2328 assert(cache_info->signature == MagickSignature);
2329 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2330 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2331 (GetOneVirtualPixelFromHandler) NULL)
2332 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2333 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2334 assert(id < (int) cache_info->number_threads);
2335 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2336 1UL,1UL,cache_info->nexus_info[id],exception);
2337 if (p == (const Quantum *) NULL)
2339 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2340 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2341 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2342 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2343 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2344 return(MagickFalse);
2346 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2351 channel=GetPixelChannelMapChannel(image,i);
2352 pixel[channel]=p[i];
2358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2362 + 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 %
2366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2368 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2369 % specified (x,y) location. The image background color is returned if an
2372 % The format of the GetOneVirtualPixelFromCache() method is:
2374 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2375 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
2376 % Quantum *pixel,ExceptionInfo *exception)
2378 % A description of each parameter follows:
2380 % o image: the image.
2382 % o virtual_pixel_method: the virtual pixel method.
2384 % o x,y: These values define the location of the pixel to return.
2386 % o pixel: return a pixel at the specified (x,y) location.
2388 % o exception: return any errors or warnings in this structure.
2391 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2392 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2393 Quantum *pixel,ExceptionInfo *exception)
2399 id = GetOpenMPThreadId();
2407 assert(image != (const Image *) NULL);
2408 assert(image->signature == MagickSignature);
2409 assert(image->cache != (Cache) NULL);
2410 cache_info=(CacheInfo *) image->cache;
2411 assert(cache_info->signature == MagickSignature);
2412 assert(id < (int) cache_info->number_threads);
2413 (void) memset(pixel,0,MaxPixelChannels*sizeof(*pixel));
2414 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2415 cache_info->nexus_info[id],exception);
2416 if (p == (const Quantum *) NULL)
2418 pixel[RedPixelChannel]=ClampToQuantum(image->background_color.red);
2419 pixel[GreenPixelChannel]=ClampToQuantum(image->background_color.green);
2420 pixel[BluePixelChannel]=ClampToQuantum(image->background_color.blue);
2421 pixel[BlackPixelChannel]=ClampToQuantum(image->background_color.black);
2422 pixel[AlphaPixelChannel]=ClampToQuantum(image->background_color.alpha);
2423 return(MagickFalse);
2425 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2430 channel=GetPixelChannelMapChannel(image,i);
2431 pixel[channel]=p[i];
2437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2441 % G e t O n e V i r t u a l P i x e l I n f o %
2445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2447 % GetOneVirtualPixelInfo() returns a single pixel at the specified (x,y)
2448 % location. The image background color is returned if an error occurs. If
2449 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2451 % The format of the GetOneVirtualPixelInfo() method is:
2453 % MagickBooleanType GetOneVirtualPixelInfo(const Image image,
2454 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2455 % const ssize_t y,PixelInfo *pixel,ExceptionInfo exception)
2457 % A description of each parameter follows:
2459 % o image: the image.
2461 % o virtual_pixel_method: the virtual pixel method.
2463 % o x,y: these values define the location of the pixel to return.
2465 % o pixel: return a pixel at the specified (x,y) location.
2467 % o exception: return any errors or warnings in this structure.
2470 MagickExport MagickBooleanType GetOneVirtualPixelInfo(const Image *image,
2471 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2472 PixelInfo *pixel,ExceptionInfo *exception)
2478 id = GetOpenMPThreadId();
2480 register const Quantum
2483 assert(image != (const Image *) NULL);
2484 assert(image->signature == MagickSignature);
2485 assert(image->cache != (Cache) NULL);
2486 cache_info=(CacheInfo *) image->cache;
2487 assert(cache_info->signature == MagickSignature);
2488 assert(id < (int) cache_info->number_threads);
2489 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2490 cache_info->nexus_info[id],exception);
2491 GetPixelInfo(image,pixel);
2492 if (p == (const Quantum *) NULL)
2493 return(MagickFalse);
2494 GetPixelInfoPixel(image,p,pixel);
2499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2503 + G e t P i x e l C a c h e C o l o r s p a c e %
2507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2509 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2511 % The format of the GetPixelCacheColorspace() method is:
2513 % Colorspace GetPixelCacheColorspace(Cache cache)
2515 % A description of each parameter follows:
2517 % o cache: the pixel cache.
2520 MagickPrivate ColorspaceType GetPixelCacheColorspace(const Cache cache)
2525 assert(cache != (Cache) NULL);
2526 cache_info=(CacheInfo *) cache;
2527 assert(cache_info->signature == MagickSignature);
2528 if (cache_info->debug != MagickFalse)
2529 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2530 cache_info->filename);
2531 return(cache_info->colorspace);
2535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2539 + G e t P i x e l C a c h e M e t h o d s %
2543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2545 % GetPixelCacheMethods() initializes the CacheMethods structure.
2547 % The format of the GetPixelCacheMethods() method is:
2549 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2551 % A description of each parameter follows:
2553 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2556 MagickPrivate void GetPixelCacheMethods(CacheMethods *cache_methods)
2558 assert(cache_methods != (CacheMethods *) NULL);
2559 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2560 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2561 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2562 cache_methods->get_virtual_metacontent_from_handler=
2563 GetVirtualMetacontentFromCache;
2564 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2565 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2566 cache_methods->get_authentic_metacontent_from_handler=
2567 GetAuthenticMetacontentFromCache;
2568 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2569 cache_methods->get_one_authentic_pixel_from_handler=
2570 GetOneAuthenticPixelFromCache;
2571 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2572 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2573 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2581 + G e t P i x e l C a c h e N e x u s E x t e n t %
2585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2587 % GetPixelCacheNexusExtent() returns the extent of the pixels associated
2588 % corresponding with the last call to SetPixelCacheNexusPixels() or
2589 % GetPixelCacheNexusPixels().
2591 % The format of the GetPixelCacheNexusExtent() method is:
2593 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2594 % NexusInfo *nexus_info)
2596 % A description of each parameter follows:
2598 % o nexus_info: the nexus info.
2601 MagickPrivate MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2602 NexusInfo *nexus_info)
2610 assert(cache != NULL);
2611 cache_info=(CacheInfo *) cache;
2612 assert(cache_info->signature == MagickSignature);
2613 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2615 return((MagickSizeType) cache_info->columns*cache_info->rows);
2620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2624 + 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 %
2628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2630 % GetPixelCacheNexusMetacontent() returns the meta-content for the specified
2633 % The format of the GetPixelCacheNexusMetacontent() method is:
2635 % void *GetPixelCacheNexusMetacontent(const Cache cache,
2636 % NexusInfo *nexus_info)
2638 % A description of each parameter follows:
2640 % o cache: the pixel cache.
2642 % o nexus_info: the cache nexus to return the meta-content.
2645 MagickPrivate void *GetPixelCacheNexusMetacontent(const Cache cache,
2646 NexusInfo *nexus_info)
2651 assert(cache != NULL);
2652 cache_info=(CacheInfo *) cache;
2653 assert(cache_info->signature == MagickSignature);
2654 if (cache_info->storage_class == UndefinedClass)
2655 return((void *) NULL);
2656 return(nexus_info->metacontent);
2660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2664 + G e t P i x e l C a c h e N e x u s P i x e l s %
2668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2670 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2673 % The format of the GetPixelCacheNexusPixels() method is:
2675 % Quantum *GetPixelCacheNexusPixels(const Cache cache,
2676 % NexusInfo *nexus_info)
2678 % A description of each parameter follows:
2680 % o cache: the pixel cache.
2682 % o nexus_info: the cache nexus to return the pixels.
2685 MagickPrivate Quantum *GetPixelCacheNexusPixels(const Cache cache,
2686 NexusInfo *nexus_info)
2691 assert(cache != NULL);
2692 cache_info=(CacheInfo *) cache;
2693 assert(cache_info->signature == MagickSignature);
2694 if (cache_info->storage_class == UndefinedClass)
2695 return((Quantum *) NULL);
2696 return(nexus_info->pixels);
2700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2704 + G e t P i x e l C a c h e P i x e l s %
2708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2710 % GetPixelCachePixels() returns the pixels associated with the specified image.
2712 % The format of the GetPixelCachePixels() method is:
2714 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2715 % ExceptionInfo *exception)
2717 % A description of each parameter follows:
2719 % o image: the image.
2721 % o length: the pixel cache length.
2723 % o exception: return any errors or warnings in this structure.
2726 MagickPrivate void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2727 ExceptionInfo *exception)
2732 assert(image != (const Image *) NULL);
2733 assert(image->signature == MagickSignature);
2734 assert(image->cache != (Cache) NULL);
2735 assert(length != (MagickSizeType *) NULL);
2736 assert(exception != (ExceptionInfo *) NULL);
2737 assert(exception->signature == MagickSignature);
2738 cache_info=(CacheInfo *) image->cache;
2739 assert(cache_info->signature == MagickSignature);
2741 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2742 return((void *) NULL);
2743 *length=cache_info->length;
2744 return((void *) cache_info->pixels);
2748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2752 + 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 %
2756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2758 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2760 % The format of the GetPixelCacheStorageClass() method is:
2762 % ClassType GetPixelCacheStorageClass(Cache cache)
2764 % A description of each parameter follows:
2766 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2768 % o cache: the pixel cache.
2771 MagickPrivate ClassType GetPixelCacheStorageClass(const Cache cache)
2776 assert(cache != (Cache) NULL);
2777 cache_info=(CacheInfo *) cache;
2778 assert(cache_info->signature == MagickSignature);
2779 if (cache_info->debug != MagickFalse)
2780 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2781 cache_info->filename);
2782 return(cache_info->storage_class);
2786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2790 + G e t P i x e l C a c h e T i l e S i z e %
2794 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2796 % GetPixelCacheTileSize() returns the pixel cache tile size.
2798 % The format of the GetPixelCacheTileSize() method is:
2800 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2803 % A description of each parameter follows:
2805 % o image: the image.
2807 % o width: the optimize cache tile width in pixels.
2809 % o height: the optimize cache tile height in pixels.
2812 MagickPrivate void GetPixelCacheTileSize(const Image *image,size_t *width,
2818 assert(image != (Image *) NULL);
2819 assert(image->signature == MagickSignature);
2820 if (image->debug != MagickFalse)
2821 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2822 cache_info=(CacheInfo *) image->cache;
2823 assert(cache_info->signature == MagickSignature);
2824 *width=2048UL/(cache_info->number_channels*sizeof(Quantum));
2825 if (GetPixelCacheType(image) == DiskCache)
2826 *width=8192UL/(cache_info->number_channels*sizeof(Quantum));
2831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2835 + G e t P i x e l C a c h e T y p e %
2839 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2841 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2843 % The format of the GetPixelCacheType() method is:
2845 % CacheType GetPixelCacheType(const Image *image)
2847 % A description of each parameter follows:
2849 % o image: the image.
2852 MagickPrivate CacheType GetPixelCacheType(const Image *image)
2857 assert(image != (Image *) NULL);
2858 assert(image->signature == MagickSignature);
2859 assert(image->cache != (Cache) NULL);
2860 cache_info=(CacheInfo *) image->cache;
2861 assert(cache_info->signature == MagickSignature);
2862 return(cache_info->type);
2866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2870 + 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 %
2874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2876 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2877 % pixel cache. A virtual pixel is any pixel access that is outside the
2878 % boundaries of the image cache.
2880 % The format of the GetPixelCacheVirtualMethod() method is:
2882 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2884 % A description of each parameter follows:
2886 % o image: the image.
2889 MagickPrivate VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2894 assert(image != (Image *) NULL);
2895 assert(image->signature == MagickSignature);
2896 assert(image->cache != (Cache) NULL);
2897 cache_info=(CacheInfo *) image->cache;
2898 assert(cache_info->signature == MagickSignature);
2899 return(cache_info->virtual_pixel_method);
2903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2907 + 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 %
2911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2913 % GetVirtualMetacontentFromCache() returns the meta-content corresponding with
2914 % the last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2916 % The format of the GetVirtualMetacontentFromCache() method is:
2918 % void *GetVirtualMetacontentFromCache(const Image *image)
2920 % A description of each parameter follows:
2922 % o image: the image.
2925 static const void *GetVirtualMetacontentFromCache(const Image *image)
2931 id = GetOpenMPThreadId();
2936 assert(image != (const Image *) NULL);
2937 assert(image->signature == MagickSignature);
2938 assert(image->cache != (Cache) NULL);
2939 cache_info=(CacheInfo *) image->cache;
2940 assert(cache_info->signature == MagickSignature);
2941 assert(id < (int) cache_info->number_threads);
2942 metacontent=GetVirtualMetacontentFromNexus(cache_info,
2943 cache_info->nexus_info[id]);
2944 return(metacontent);
2948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2952 + 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 %
2956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2958 % GetVirtualMetacontentFromNexus() returns the meta-content for the specified
2961 % The format of the GetVirtualMetacontentFromNexus() method is:
2963 % const void *GetVirtualMetacontentFromNexus(const Cache cache,
2964 % NexusInfo *nexus_info)
2966 % A description of each parameter follows:
2968 % o cache: the pixel cache.
2970 % o nexus_info: the cache nexus to return the meta-content.
2973 MagickPrivate const void *GetVirtualMetacontentFromNexus(const Cache cache,
2974 NexusInfo *nexus_info)
2979 assert(cache != (Cache) NULL);
2980 cache_info=(CacheInfo *) cache;
2981 assert(cache_info->signature == MagickSignature);
2982 if (cache_info->storage_class == UndefinedClass)
2983 return((void *) NULL);
2984 return(nexus_info->metacontent);
2988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2992 % G e t V i r t u a l M e t a c o n t e n t %
2996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2998 % GetVirtualMetacontent() returns the virtual metacontent corresponding with
2999 % the last call to QueueAuthenticPixels() or GetVirtualPixels(). NULL is
3000 % returned if the meta-content are not available.
3002 % The format of the GetVirtualMetacontent() method is:
3004 % const void *GetVirtualMetacontent(const Image *image)
3006 % A description of each parameter follows:
3008 % o image: the image.
3011 MagickExport const void *GetVirtualMetacontent(const Image *image)
3017 id = GetOpenMPThreadId();
3022 assert(image != (const Image *) NULL);
3023 assert(image->signature == MagickSignature);
3024 assert(image->cache != (Cache) NULL);
3025 cache_info=(CacheInfo *) image->cache;
3026 assert(cache_info->signature == MagickSignature);
3027 if (cache_info->methods.get_virtual_metacontent_from_handler !=
3028 (GetVirtualMetacontentFromHandler) NULL)
3030 metacontent=cache_info->methods.
3031 get_virtual_metacontent_from_handler(image);
3032 return(metacontent);
3034 assert(id < (int) cache_info->number_threads);
3035 metacontent=GetVirtualMetacontentFromNexus(cache_info,
3036 cache_info->nexus_info[id]);
3037 return(metacontent);
3041 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3045 + 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 %
3049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3051 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3052 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3053 % is returned if the pixels are transferred, otherwise a NULL is returned.
3055 % The format of the GetVirtualPixelsFromNexus() method is:
3057 % Quantum *GetVirtualPixelsFromNexus(const Image *image,
3058 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3059 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
3060 % ExceptionInfo *exception)
3062 % A description of each parameter follows:
3064 % o image: the image.
3066 % o virtual_pixel_method: the virtual pixel method.
3068 % o x,y,columns,rows: These values define the perimeter of a region of
3071 % o nexus_info: the cache nexus to acquire.
3073 % o exception: return any errors or warnings in this structure.
3080 0, 48, 12, 60, 3, 51, 15, 63,
3081 32, 16, 44, 28, 35, 19, 47, 31,
3082 8, 56, 4, 52, 11, 59, 7, 55,
3083 40, 24, 36, 20, 43, 27, 39, 23,
3084 2, 50, 14, 62, 1, 49, 13, 61,
3085 34, 18, 46, 30, 33, 17, 45, 29,
3086 10, 58, 6, 54, 9, 57, 5, 53,
3087 42, 26, 38, 22, 41, 25, 37, 21
3090 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3095 index=x+DitherMatrix[x & 0x07]-32L;
3098 if (index >= (ssize_t) columns)
3099 return((ssize_t) columns-1L);
3103 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3108 index=y+DitherMatrix[y & 0x07]-32L;
3111 if (index >= (ssize_t) rows)
3112 return((ssize_t) rows-1L);
3116 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3120 if (x >= (ssize_t) columns)
3121 return((ssize_t) (columns-1));
3125 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3129 if (y >= (ssize_t) rows)
3130 return((ssize_t) (rows-1));
3134 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3136 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3139 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3141 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3144 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3145 const size_t extent)
3151 Compute the remainder of dividing offset by extent. It returns not only
3152 the quotient (tile the offset falls in) but also the positive remainer
3153 within that tile such that 0 <= remainder < extent. This method is
3154 essentially a ldiv() using a floored modulo division rather than the
3155 normal default truncated modulo division.
3157 modulo.quotient=offset/(ssize_t) extent;
3160 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3164 MagickPrivate const Quantum *GetVirtualPixelsFromNexus(const Image *image,
3165 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3166 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3167 ExceptionInfo *exception)
3184 virtual_pixel[CompositePixelChannel];
3189 register const Quantum
3202 register unsigned char
3209 *virtual_metacontent;
3214 assert(image != (const Image *) NULL);
3215 assert(image->signature == MagickSignature);
3216 assert(image->cache != (Cache) NULL);
3217 cache_info=(CacheInfo *) image->cache;
3218 assert(cache_info->signature == MagickSignature);
3219 if (cache_info->type == UndefinedCache)
3220 return((const Quantum *) NULL);
3223 region.width=columns;
3225 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3226 if (pixels == (Quantum *) NULL)
3227 return((const Quantum *) NULL);
3229 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3230 nexus_info->region.x;
3231 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3232 nexus_info->region.width-1L;
3233 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3234 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3235 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3236 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3242 Pixel request is inside cache extents.
3244 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
3246 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3247 if (status == MagickFalse)
3248 return((const Quantum *) NULL);
3249 if (cache_info->metacontent_extent != 0)
3251 status=ReadPixelCacheMetacontent(cache_info,nexus_info,exception);
3252 if (status == MagickFalse)
3253 return((const Quantum *) NULL);
3258 Pixel request is outside cache extents.
3260 s=(unsigned char *) GetPixelCacheNexusMetacontent(cache_info,nexus_info);
3261 virtual_nexus=AcquirePixelCacheNexus(1);
3262 if (virtual_nexus == (NexusInfo **) NULL)
3264 if (virtual_nexus != (NexusInfo **) NULL)
3265 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3266 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3267 "UnableToGetCacheNexus","`%s'",image->filename);
3268 return((const Quantum *) NULL);
3270 (void) ResetMagickMemory(virtual_pixel,0,cache_info->number_channels*
3271 sizeof(*virtual_pixel));
3272 virtual_metacontent=(void *) NULL;
3273 switch (virtual_pixel_method)
3275 case BackgroundVirtualPixelMethod:
3276 case BlackVirtualPixelMethod:
3277 case GrayVirtualPixelMethod:
3278 case TransparentVirtualPixelMethod:
3279 case MaskVirtualPixelMethod:
3280 case WhiteVirtualPixelMethod:
3281 case EdgeVirtualPixelMethod:
3282 case CheckerTileVirtualPixelMethod:
3283 case HorizontalTileVirtualPixelMethod:
3284 case VerticalTileVirtualPixelMethod:
3286 if (cache_info->metacontent_extent != 0)
3289 Acquire a metacontent buffer.
3291 virtual_metacontent=(void *) AcquireQuantumMemory(1,
3292 cache_info->metacontent_extent);
3293 if (virtual_metacontent == (void *) NULL)
3295 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3296 (void) ThrowMagickException(exception,GetMagickModule(),
3297 CacheError,"UnableToGetCacheNexus","`%s'",image->filename);
3298 return((const Quantum *) NULL);
3300 (void) ResetMagickMemory(virtual_metacontent,0,
3301 cache_info->metacontent_extent);
3303 switch (virtual_pixel_method)
3305 case BlackVirtualPixelMethod:
3307 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3308 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3309 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3312 case GrayVirtualPixelMethod:
3314 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3315 SetPixelChannel(image,(PixelChannel) i,QuantumRange/2,
3317 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3320 case TransparentVirtualPixelMethod:
3322 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3323 SetPixelChannel(image,(PixelChannel) i,0,virtual_pixel);
3324 SetPixelAlpha(image,TransparentAlpha,virtual_pixel);
3327 case MaskVirtualPixelMethod:
3328 case WhiteVirtualPixelMethod:
3330 for (i=0; i < (ssize_t) cache_info->number_channels; i++)
3331 SetPixelChannel(image,(PixelChannel) i,QuantumRange,virtual_pixel);
3332 SetPixelAlpha(image,OpaqueAlpha,virtual_pixel);
3337 SetPixelRed(image,ClampToQuantum(image->background_color.red),
3339 SetPixelGreen(image,ClampToQuantum(image->background_color.green),
3341 SetPixelBlue(image,ClampToQuantum(image->background_color.blue),
3343 if (image->colorspace == CMYKColorspace)
3344 SetPixelBlack(image,ClampToQuantum(image->background_color.black),
3346 SetPixelAlpha(image,ClampToQuantum(image->background_color.alpha),
3356 for (v=0; v < (ssize_t) rows; v++)
3358 for (u=0; u < (ssize_t) columns; u+=length)
3360 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3361 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3362 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3370 Transfer a single pixel.
3372 length=(MagickSizeType) 1;
3373 switch (virtual_pixel_method)
3377 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3378 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3379 1UL,1UL,*virtual_nexus,exception);
3380 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3383 case RandomVirtualPixelMethod:
3385 if (cache_info->random_info == (RandomInfo *) NULL)
3386 cache_info->random_info=AcquireRandomInfo();
3387 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3388 RandomX(cache_info->random_info,cache_info->columns),
3389 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3390 *virtual_nexus,exception);
3391 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3394 case DitherVirtualPixelMethod:
3396 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3397 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3398 1UL,1UL,*virtual_nexus,exception);
3399 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3402 case TileVirtualPixelMethod:
3404 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3405 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3406 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3407 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3409 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3412 case MirrorVirtualPixelMethod:
3414 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3415 if ((x_modulo.quotient & 0x01) == 1L)
3416 x_modulo.remainder=(ssize_t) cache_info->columns-
3417 x_modulo.remainder-1L;
3418 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3419 if ((y_modulo.quotient & 0x01) == 1L)
3420 y_modulo.remainder=(ssize_t) cache_info->rows-
3421 y_modulo.remainder-1L;
3422 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3423 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3425 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3428 case HorizontalTileEdgeVirtualPixelMethod:
3430 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3431 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3432 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3433 *virtual_nexus,exception);
3434 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3437 case VerticalTileEdgeVirtualPixelMethod:
3439 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3440 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3441 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3442 *virtual_nexus,exception);
3443 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3446 case BackgroundVirtualPixelMethod:
3447 case BlackVirtualPixelMethod:
3448 case GrayVirtualPixelMethod:
3449 case TransparentVirtualPixelMethod:
3450 case MaskVirtualPixelMethod:
3451 case WhiteVirtualPixelMethod:
3454 r=virtual_metacontent;
3457 case EdgeVirtualPixelMethod:
3458 case CheckerTileVirtualPixelMethod:
3460 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3461 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3462 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3465 r=virtual_metacontent;
3468 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3469 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3471 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3474 case HorizontalTileVirtualPixelMethod:
3476 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3479 r=virtual_metacontent;
3482 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3483 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3484 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3485 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3487 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3490 case VerticalTileVirtualPixelMethod:
3492 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3495 r=virtual_metacontent;
3498 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3499 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3500 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3501 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3503 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3507 if (p == (const Quantum *) NULL)
3509 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*
3511 q+=cache_info->number_channels;
3512 if ((s != (void *) NULL) && (r != (const void *) NULL))
3514 (void) memcpy(s,r,(size_t) cache_info->metacontent_extent);
3515 s+=cache_info->metacontent_extent;
3520 Transfer a run of pixels.
3522 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,(size_t)
3523 length,1UL,*virtual_nexus,exception);
3524 if (p == (const Quantum *) NULL)
3526 r=GetVirtualMetacontentFromNexus(cache_info,*virtual_nexus);
3527 (void) memcpy(q,p,(size_t) length*cache_info->number_channels*sizeof(*p));
3528 q+=length*cache_info->number_channels;
3529 if ((r != (void *) NULL) && (s != (const void *) NULL))
3531 (void) memcpy(s,r,(size_t) length);
3532 s+=length*cache_info->metacontent_extent;
3539 if (virtual_metacontent != (void *) NULL)
3540 virtual_metacontent=(void *) RelinquishMagickMemory(virtual_metacontent);
3541 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3550 + G e t V i r t u a l P i x e l C a c h e %
3554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3556 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3557 % cache as defined by the geometry parameters. A pointer to the pixels
3558 % is returned if the pixels are transferred, otherwise a NULL is returned.
3560 % The format of the GetVirtualPixelCache() method is:
3562 % const Quantum *GetVirtualPixelCache(const Image *image,
3563 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3564 % const ssize_t y,const size_t columns,const size_t rows,
3565 % ExceptionInfo *exception)
3567 % A description of each parameter follows:
3569 % o image: the image.
3571 % o virtual_pixel_method: the virtual pixel method.
3573 % o x,y,columns,rows: These values define the perimeter of a region of
3576 % o exception: return any errors or warnings in this structure.
3579 static const Quantum *GetVirtualPixelCache(const Image *image,
3580 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3581 const size_t columns,const size_t rows,ExceptionInfo *exception)
3587 id = GetOpenMPThreadId();
3592 assert(image != (const Image *) NULL);
3593 assert(image->signature == MagickSignature);
3594 assert(image->cache != (Cache) NULL);
3595 cache_info=(CacheInfo *) image->cache;
3596 assert(cache_info->signature == MagickSignature);
3597 assert(id < (int) cache_info->number_threads);
3598 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3599 cache_info->nexus_info[id],exception);
3604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3608 % G e t V i r t u a l P i x e l Q u e u e %
3612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614 % GetVirtualPixelQueue() returns the virtual pixels associated corresponding
3615 % with the last call to QueueAuthenticPixels() or GetVirtualPixels().
3617 % The format of the GetVirtualPixelQueue() method is:
3619 % const Quantum *GetVirtualPixelQueue(const Image image)
3621 % A description of each parameter follows:
3623 % o image: the image.
3626 MagickExport const Quantum *GetVirtualPixelQueue(const Image *image)
3632 id = GetOpenMPThreadId();
3634 assert(image != (const Image *) NULL);
3635 assert(image->signature == MagickSignature);
3636 assert(image->cache != (Cache) NULL);
3637 cache_info=(CacheInfo *) image->cache;
3638 assert(cache_info->signature == MagickSignature);
3639 if (cache_info->methods.get_virtual_pixels_handler !=
3640 (GetVirtualPixelsHandler) NULL)
3641 return(cache_info->methods.get_virtual_pixels_handler(image));
3642 assert(id < (int) cache_info->number_threads);
3643 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3647 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3651 % G e t V i r t u a l P i x e l s %
3655 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3657 % GetVirtualPixels() returns an immutable pixel region. If the
3658 % region is successfully accessed, a pointer to it is returned, otherwise
3659 % NULL is returned. The returned pointer may point to a temporary working
3660 % copy of the pixels or it may point to the original pixels in memory.
3661 % Performance is maximized if the selected region is part of one row, or one
3662 % or more full rows, since there is opportunity to access the pixels in-place
3663 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3664 % returned pointer must *never* be deallocated by the user.
3666 % Pixels accessed via the returned pointer represent a simple array of type
3667 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
3668 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
3669 % access the meta-content (of type void) corresponding to the the
3672 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3674 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3675 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3676 % GetCacheViewAuthenticPixels() instead.
3678 % The format of the GetVirtualPixels() method is:
3680 % const Quantum *GetVirtualPixels(const Image *image,const ssize_t x,
3681 % const ssize_t y,const size_t columns,const size_t rows,
3682 % ExceptionInfo *exception)
3684 % A description of each parameter follows:
3686 % o image: the image.
3688 % o x,y,columns,rows: These values define the perimeter of a region of
3691 % o exception: return any errors or warnings in this structure.
3694 MagickExport const Quantum *GetVirtualPixels(const Image *image,
3695 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3696 ExceptionInfo *exception)
3702 id = GetOpenMPThreadId();
3707 assert(image != (const Image *) NULL);
3708 assert(image->signature == MagickSignature);
3709 assert(image->cache != (Cache) NULL);
3710 cache_info=(CacheInfo *) image->cache;
3711 assert(cache_info->signature == MagickSignature);
3712 if (cache_info->methods.get_virtual_pixel_handler !=
3713 (GetVirtualPixelHandler) NULL)
3714 return(cache_info->methods.get_virtual_pixel_handler(image,
3715 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3716 assert(id < (int) cache_info->number_threads);
3717 p=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3718 columns,rows,cache_info->nexus_info[id],exception);
3723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3727 + 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 %
3731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3733 % GetVirtualPixelsCache() returns the pixels associated corresponding with the
3734 % last call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3736 % The format of the GetVirtualPixelsCache() method is:
3738 % Quantum *GetVirtualPixelsCache(const Image *image)
3740 % A description of each parameter follows:
3742 % o image: the image.
3745 static const Quantum *GetVirtualPixelsCache(const Image *image)
3751 id = GetOpenMPThreadId();
3753 assert(image != (const Image *) NULL);
3754 assert(image->signature == MagickSignature);
3755 assert(image->cache != (Cache) NULL);
3756 cache_info=(CacheInfo *) image->cache;
3757 assert(cache_info->signature == MagickSignature);
3758 assert(id < (int) cache_info->number_threads);
3759 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3767 + G e t V i r t u a l P i x e l s N e x u s %
3771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3773 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3776 % The format of the GetVirtualPixelsNexus() method is:
3778 % const Quantum *GetVirtualPixelsNexus(const Cache cache,
3779 % NexusInfo *nexus_info)
3781 % A description of each parameter follows:
3783 % o cache: the pixel cache.
3785 % o nexus_info: the cache nexus to return the colormap pixels.
3788 MagickPrivate const Quantum *GetVirtualPixelsNexus(const Cache cache,
3789 NexusInfo *nexus_info)
3794 assert(cache != (Cache) NULL);
3795 cache_info=(CacheInfo *) cache;
3796 assert(cache_info->signature == MagickSignature);
3797 if (cache_info->storage_class == UndefinedClass)
3798 return((Quantum *) NULL);
3799 return((const Quantum *) nexus_info->pixels);
3803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3807 + M a s k P i x e l C a c h e N e x u s %
3811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3813 % MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3814 % The method returns MagickTrue if the pixel region is masked, otherwise
3817 % The format of the MaskPixelCacheNexus() method is:
3819 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3820 % NexusInfo *nexus_info,ExceptionInfo *exception)
3822 % A description of each parameter follows:
3824 % o image: the image.
3826 % o nexus_info: the cache nexus to clip.
3828 % o exception: return any errors or warnings in this structure.
3831 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3832 ExceptionInfo *exception)
3844 register const Quantum
3855 Prevent updates to image pixels specified by the mask.
3857 if (image->debug != MagickFalse)
3858 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3859 if (image->mask == (Image *) NULL)
3860 return(MagickFalse);
3861 cache_info=(CacheInfo *) image->cache;
3862 if (cache_info == (Cache) NULL)
3863 return(MagickFalse);
3864 image_nexus=AcquirePixelCacheNexus(1);
3865 clip_nexus=AcquirePixelCacheNexus(1);
3866 if ((image_nexus == (NexusInfo **) NULL) ||
3867 (clip_nexus == (NexusInfo **) NULL))
3868 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3869 p=(const Quantum *) GetAuthenticPixelCacheNexus(image,
3870 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3871 nexus_info->region.height,image_nexus[0],exception);
3872 q=nexus_info->pixels;
3873 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3874 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3875 nexus_info->region.height,clip_nexus[0],exception);
3876 number_pixels=(MagickSizeType) nexus_info->region.width*
3877 nexus_info->region.height;
3878 for (x=0; x < (ssize_t) number_pixels; x++)
3889 if ((p == (const Quantum *) NULL) || (r == (const Quantum *) NULL))
3891 Sa=QuantumScale*GetPixelIntensity(image->mask,r);
3892 Da=QuantumScale*GetPixelAlpha(image,q);
3893 alpha=Sa*(-Da)+Sa+Da;
3894 gamma=1.0/(fabs(alpha) <= MagickEpsilon ? 1.0 : alpha);
3895 for (i=0; i < (ssize_t) image->number_channels; i++)
3908 channel=GetPixelChannelMapChannel(image,i);
3909 traits=GetPixelChannelMapTraits(image,channel);
3910 if (traits == UndefinedPixelTrait)
3912 Sc=(MagickRealType) p[i];
3913 Dc=(MagickRealType) q[i];
3914 pixel=gamma*(Sa*Sc-Sa*Da*Dc+Da*Dc);
3915 q[i]=ClampToQuantum(pixel);
3917 p+=GetPixelChannels(image);
3918 q+=GetPixelChannels(image);
3919 r+=GetPixelChannels(image->mask);
3921 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3922 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3923 if (x < (ssize_t) number_pixels)
3924 return(MagickFalse);
3929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3933 + O p e n P i x e l C a c h e %
3937 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3939 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3940 % dimensions, allocating space for the image pixels and optionally the
3941 % metacontent, and memory mapping the cache if it is disk based. The cache
3942 % nexus array is initialized as well.
3944 % The format of the OpenPixelCache() method is:
3946 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3947 % ExceptionInfo *exception)
3949 % A description of each parameter follows:
3951 % o image: the image.
3953 % o mode: ReadMode, WriteMode, or IOMode.
3955 % o exception: return any errors or warnings in this structure.
3959 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3961 cache_info->mapped=MagickFalse;
3962 cache_info->pixels=(Quantum *) AcquireQuantumMemory(1,(size_t)
3963 cache_info->length);
3964 if (cache_info->pixels == (Quantum *) NULL)
3966 cache_info->mapped=MagickTrue;
3967 cache_info->pixels=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
3968 cache_info->length);
3972 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3982 cache_info=(CacheInfo *) image->cache;
3983 if (image->debug != MagickFalse)
3986 format[MaxTextExtent],
3987 message[MaxTextExtent];
3989 (void) FormatMagickSize(length,MagickFalse,format);
3990 (void) FormatLocaleString(message,MaxTextExtent,
3991 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3992 cache_info->cache_filename,cache_info->file,format);
3993 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3995 if (length != (MagickSizeType) ((MagickOffsetType) length))
3996 return(MagickFalse);
3997 extent=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3999 return(MagickFalse);
4000 if ((MagickSizeType) extent >= length)
4002 offset=(MagickOffsetType) length-1;
4003 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4004 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4007 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4008 ExceptionInfo *exception)
4015 format[MaxTextExtent],
4016 message[MaxTextExtent];
4033 assert(image != (const Image *) NULL);
4034 assert(image->signature == MagickSignature);
4035 assert(image->cache != (Cache) NULL);
4036 if (image->debug != MagickFalse)
4037 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4038 if ((image->columns == 0) || (image->rows == 0))
4039 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4040 cache_info=(CacheInfo *) image->cache;
4041 assert(cache_info->signature == MagickSignature);
4042 source_info=(*cache_info);
4043 source_info.file=(-1);
4044 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4045 image->filename,(double) GetImageIndexInList(image));
4046 cache_info->storage_class=image->storage_class;
4047 cache_info->colorspace=image->colorspace;
4048 cache_info->matte=image->matte;
4049 cache_info->rows=image->rows;
4050 cache_info->columns=image->columns;
4051 InitializePixelChannelMap(image);
4052 cache_info->number_channels=GetPixelChannels(image);
4053 (void) memcpy(cache_info->channel_map,image->channel_map,MaxPixelChannels*
4054 sizeof(*image->channel_map));
4055 cache_info->metacontent_extent=image->metacontent_extent;
4056 cache_info->mode=mode;
4057 if (image->ping != MagickFalse)
4059 cache_info->type=PingCache;
4060 cache_info->pixels=(Quantum *) NULL;
4061 cache_info->metacontent=(void *) NULL;
4062 cache_info->length=0;
4065 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4066 packet_size=cache_info->number_channels*sizeof(Quantum);
4067 if (image->metacontent_extent != 0)
4068 packet_size+=cache_info->metacontent_extent;
4069 length=number_pixels*packet_size;
4070 columns=(size_t) (length/cache_info->rows/packet_size);
4071 if (cache_info->columns != columns)
4072 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4074 cache_info->length=length;
4075 p=cache_info->channel_map;
4076 q=source_info.channel_map;
4077 if ((cache_info->type != UndefinedCache) &&
4078 (cache_info->columns <= source_info.columns) &&
4079 (cache_info->rows <= source_info.rows) &&
4080 (cache_info->number_channels <= source_info.number_channels) &&
4081 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
4082 (cache_info->metacontent_extent <= source_info.metacontent_extent))
4085 Inline pixel cache clone optimization.
4087 if ((cache_info->columns == source_info.columns) &&
4088 (cache_info->rows == source_info.rows) &&
4089 (cache_info->number_channels == source_info.number_channels) &&
4090 (memcmp(p,q,cache_info->number_channels*sizeof(*p)) == 0) &&
4091 (cache_info->metacontent_extent == source_info.metacontent_extent))
4093 return(ClonePixelCachePixels(cache_info,&source_info,exception));
4095 status=AcquireMagickResource(AreaResource,cache_info->length);
4096 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4097 cache_info->metacontent_extent);
4098 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4100 status=AcquireMagickResource(MemoryResource,cache_info->length);
4101 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4102 (cache_info->type == MemoryCache))
4104 AllocatePixelCachePixels(cache_info);
4105 if (cache_info->pixels == (Quantum *) NULL)
4106 cache_info->pixels=source_info.pixels;
4110 Create memory pixel cache.
4113 if (image->debug != MagickFalse)
4115 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
4116 (void) FormatLocaleString(message,MaxTextExtent,
4117 "open %s (%s memory, %.20gx%.20gx%.20g %s)",
4118 cache_info->filename,cache_info->mapped != MagickFalse ?
4119 "anonymous" : "heap",(double) cache_info->columns,(double)
4120 cache_info->rows,(double) cache_info->number_channels,
4122 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4125 cache_info->type=MemoryCache;
4126 cache_info->metacontent=(void *) NULL;
4127 if (cache_info->metacontent_extent != 0)
4128 cache_info->metacontent=(void *) (cache_info->pixels+
4129 number_pixels*cache_info->number_channels);
4130 if ((source_info.storage_class != UndefinedClass) &&
4133 status=ClonePixelCachePixels(cache_info,&source_info,
4135 RelinquishPixelCachePixels(&source_info);
4140 RelinquishMagickResource(MemoryResource,cache_info->length);
4143 Create pixel cache on disk.
4145 status=AcquireMagickResource(DiskResource,cache_info->length);
4146 if (status == MagickFalse)
4148 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4149 "CacheResourcesExhausted","`%s'",image->filename);
4150 return(MagickFalse);
4152 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4154 (void) ClosePixelCacheOnDisk(cache_info);
4155 *cache_info->cache_filename='\0';
4157 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4159 RelinquishMagickResource(DiskResource,cache_info->length);
4160 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4162 return(MagickFalse);
4164 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4165 cache_info->length);
4166 if (status == MagickFalse)
4168 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4170 return(MagickFalse);
4172 length=number_pixels*(cache_info->number_channels*sizeof(Quantum)+
4173 cache_info->metacontent_extent);
4174 if (length != (MagickSizeType) ((size_t) length))
4175 cache_info->type=DiskCache;
4178 status=AcquireMagickResource(MapResource,cache_info->length);
4179 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4180 (cache_info->type != MemoryCache))
4181 cache_info->type=DiskCache;
4184 cache_info->pixels=(Quantum *) MapBlob(cache_info->file,mode,
4185 cache_info->offset,(size_t) cache_info->length);
4186 if (cache_info->pixels == (Quantum *) NULL)
4188 cache_info->type=DiskCache;
4189 cache_info->pixels=source_info.pixels;
4194 Create file-backed memory-mapped pixel cache.
4197 (void) ClosePixelCacheOnDisk(cache_info);
4198 cache_info->type=MapCache;
4199 cache_info->mapped=MagickTrue;
4200 cache_info->metacontent=(void *) NULL;
4201 if (cache_info->metacontent_extent != 0)
4202 cache_info->metacontent=(void *) (cache_info->pixels+
4203 number_pixels*cache_info->number_channels);
4204 if ((source_info.storage_class != UndefinedClass) &&
4207 status=ClonePixelCachePixels(cache_info,&source_info,
4209 RelinquishPixelCachePixels(&source_info);
4211 if (image->debug != MagickFalse)
4213 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
4214 (void) FormatLocaleString(message,MaxTextExtent,
4215 "open %s (%s[%d], memory-mapped, %.20gx%.20gx%.20g %s)",
4216 cache_info->filename,cache_info->cache_filename,
4217 cache_info->file,(double) cache_info->columns,(double)
4218 cache_info->rows,(double) cache_info->number_channels,
4220 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4226 RelinquishMagickResource(MapResource,cache_info->length);
4229 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4231 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4232 RelinquishPixelCachePixels(&source_info);
4234 if (image->debug != MagickFalse)
4236 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4237 (void) FormatLocaleString(message,MaxTextExtent,
4238 "open %s (%s[%d], disk, %.20gx%.20gx%.20g %s)",cache_info->filename,
4239 cache_info->cache_filename,cache_info->file,(double)
4240 cache_info->columns,(double) cache_info->rows,(double)
4241 cache_info->number_channels,format);
4242 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4252 + P e r s i s t P i x e l C a c h e %
4256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4258 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4259 % persistent pixel cache is one that resides on disk and is not destroyed
4260 % when the program exits.
4262 % The format of the PersistPixelCache() method is:
4264 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4265 % const MagickBooleanType attach,MagickOffsetType *offset,
4266 % ExceptionInfo *exception)
4268 % A description of each parameter follows:
4270 % o image: the image.
4272 % o filename: the persistent pixel cache filename.
4274 % o attach: A value other than zero initializes the persistent pixel cache.
4276 % o initialize: A value other than zero initializes the persistent pixel
4279 % o offset: the offset in the persistent cache to store pixels.
4281 % o exception: return any errors or warnings in this structure.
4284 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4285 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4286 ExceptionInfo *exception)
4301 assert(image != (Image *) NULL);
4302 assert(image->signature == MagickSignature);
4303 if (image->debug != MagickFalse)
4304 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4305 assert(image->cache != (void *) NULL);
4306 assert(filename != (const char *) NULL);
4307 assert(offset != (MagickOffsetType *) NULL);
4308 page_size=GetMagickPageSize();
4309 cache_info=(CacheInfo *) image->cache;
4310 assert(cache_info->signature == MagickSignature);
4311 if (attach != MagickFalse)
4314 Attach existing persistent pixel cache.
4316 if (image->debug != MagickFalse)
4317 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4318 "attach persistent cache");
4319 (void) CopyMagickString(cache_info->cache_filename,filename,
4321 cache_info->type=DiskCache;
4322 cache_info->offset=(*offset);
4323 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4324 return(MagickFalse);
4325 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4328 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4329 (cache_info->reference_count == 1))
4331 LockSemaphoreInfo(cache_info->semaphore);
4332 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4333 (cache_info->reference_count == 1))
4339 Usurp existing persistent pixel cache.
4341 status=rename_utf8(cache_info->cache_filename,filename);
4344 (void) CopyMagickString(cache_info->cache_filename,filename,
4346 *offset+=cache_info->length+page_size-(cache_info->length %
4348 UnlockSemaphoreInfo(cache_info->semaphore);
4349 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4350 if (image->debug != MagickFalse)
4351 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4352 "Usurp resident persistent cache");
4356 UnlockSemaphoreInfo(cache_info->semaphore);
4359 Clone persistent pixel cache.
4361 clone_image=(*image);
4362 clone_info=(CacheInfo *) clone_image.cache;
4363 image->cache=ClonePixelCache(cache_info);
4364 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4365 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4366 cache_info->type=DiskCache;
4367 cache_info->offset=(*offset);
4368 cache_info=(CacheInfo *) image->cache;
4369 status=OpenPixelCache(image,IOMode,exception);
4370 if (status != MagickFalse)
4371 status=ClonePixelCachePixels(cache_info,clone_info,exception);
4372 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4373 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4382 + Q u e u e A u t h e n t i c N e x u s %
4386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4388 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4389 % by the region rectangle and returns a pointer to the region. This region is
4390 % subsequently transferred from the pixel cache with
4391 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4392 % pixels are transferred, otherwise a NULL is returned.
4394 % The format of the QueueAuthenticNexus() method is:
4396 % Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4397 % const ssize_t y,const size_t columns,const size_t rows,
4398 % const MagickBooleanType clone,NexusInfo *nexus_info,
4399 % ExceptionInfo *exception)
4401 % A description of each parameter follows:
4403 % o image: the image.
4405 % o x,y,columns,rows: These values define the perimeter of a region of
4408 % o nexus_info: the cache nexus to set.
4410 % o clone: clone the pixel cache.
4412 % o exception: return any errors or warnings in this structure.
4415 MagickPrivate Quantum *QueueAuthenticNexus(Image *image,const ssize_t x,
4416 const ssize_t y,const size_t columns,const size_t rows,
4417 const MagickBooleanType clone,NexusInfo *nexus_info,ExceptionInfo *exception)
4432 Validate pixel cache geometry.
4434 assert(image != (const Image *) NULL);
4435 assert(image->signature == MagickSignature);
4436 assert(image->cache != (Cache) NULL);
4437 cache_info=(CacheInfo *) GetImagePixelCache(image,clone,exception);
4438 if (cache_info == (Cache) NULL)
4439 return((Quantum *) NULL);
4440 assert(cache_info->signature == MagickSignature);
4441 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4443 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4444 "NoPixelsDefinedInCache","`%s'",image->filename);
4445 return((Quantum *) NULL);
4447 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4448 (y >= (ssize_t) cache_info->rows))
4450 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4451 "PixelsAreNotAuthentic","`%s'",image->filename);
4452 return((Quantum *) NULL);
4454 offset=(MagickOffsetType) y*cache_info->columns+x;
4456 return((Quantum *) NULL);
4457 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4458 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4459 if ((MagickSizeType) offset >= number_pixels)
4460 return((Quantum *) NULL);
4466 region.width=columns;
4468 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4476 + 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 %
4480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4482 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4483 % defined by the region rectangle and returns a pointer to the region. This
4484 % region is subsequently transferred from the pixel cache with
4485 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4486 % pixels are transferred, otherwise a NULL is returned.
4488 % The format of the QueueAuthenticPixelsCache() method is:
4490 % Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4491 % const ssize_t y,const size_t columns,const size_t rows,
4492 % ExceptionInfo *exception)
4494 % A description of each parameter follows:
4496 % o image: the image.
4498 % o x,y,columns,rows: These values define the perimeter of a region of
4501 % o exception: return any errors or warnings in this structure.
4504 static Quantum *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4505 const ssize_t y,const size_t columns,const size_t rows,
4506 ExceptionInfo *exception)
4512 id = GetOpenMPThreadId();
4517 assert(image != (const Image *) NULL);
4518 assert(image->signature == MagickSignature);
4519 assert(image->cache != (Cache) NULL);
4520 cache_info=(CacheInfo *) image->cache;
4521 assert(cache_info->signature == MagickSignature);
4522 assert(id < (int) cache_info->number_threads);
4523 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4524 cache_info->nexus_info[id],exception);
4529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4533 % Q u e u e A u t h e n t i c P i x e l s %
4537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4539 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4540 % successfully initialized a pointer to a Quantum array representing the
4541 % region is returned, otherwise NULL is returned. The returned pointer may
4542 % point to a temporary working buffer for the pixels or it may point to the
4543 % final location of the pixels in memory.
4545 % Write-only access means that any existing pixel values corresponding to
4546 % the region are ignored. This is useful if the initial image is being
4547 % created from scratch, or if the existing pixel values are to be
4548 % completely replaced without need to refer to their pre-existing values.
4549 % The application is free to read and write the pixel buffer returned by
4550 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4551 % initialize the pixel array values. Initializing pixel array values is the
4552 % application's responsibility.
4554 % Performance is maximized if the selected region is part of one row, or
4555 % one or more full rows, since then there is opportunity to access the
4556 % pixels in-place (without a copy) if the image is in memory, or in a
4557 % memory-mapped file. The returned pointer must *never* be deallocated
4560 % Pixels accessed via the returned pointer represent a simple array of type
4561 % Quantum. If the image type is CMYK or the storage class is PseudoClass,
4562 % call GetAuthenticMetacontent() after invoking GetAuthenticPixels() to
4563 % obtain the meta-content (of type void) corresponding to the region.
4564 % Once the Quantum (and/or Quantum) array has been updated, the
4565 % changes must be saved back to the underlying image using
4566 % SyncAuthenticPixels() or they may be lost.
4568 % The format of the QueueAuthenticPixels() method is:
4570 % Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4571 % const ssize_t y,const size_t columns,const size_t rows,
4572 % ExceptionInfo *exception)
4574 % A description of each parameter follows:
4576 % o image: the image.
4578 % o x,y,columns,rows: These values define the perimeter of a region of
4581 % o exception: return any errors or warnings in this structure.
4584 MagickExport Quantum *QueueAuthenticPixels(Image *image,const ssize_t x,
4585 const ssize_t y,const size_t columns,const size_t rows,
4586 ExceptionInfo *exception)
4592 id = GetOpenMPThreadId();
4597 assert(image != (Image *) NULL);
4598 assert(image->signature == MagickSignature);
4599 assert(image->cache != (Cache) NULL);
4600 cache_info=(CacheInfo *) image->cache;
4601 assert(cache_info->signature == MagickSignature);
4602 if (cache_info->methods.queue_authentic_pixels_handler !=
4603 (QueueAuthenticPixelsHandler) NULL)
4605 q=cache_info->methods.queue_authentic_pixels_handler(image,x,y,
4606 columns,rows,exception);
4609 assert(id < (int) cache_info->number_threads);
4610 q=QueueAuthenticNexus(image,x,y,columns,rows,MagickFalse,
4611 cache_info->nexus_info[id],exception);
4616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4620 + 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 %
4624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4626 % ReadPixelCacheMetacontent() reads metacontent from the specified region of
4629 % The format of the ReadPixelCacheMetacontent() method is:
4631 % MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4632 % NexusInfo *nexus_info,ExceptionInfo *exception)
4634 % A description of each parameter follows:
4636 % o cache_info: the pixel cache.
4638 % o nexus_info: the cache nexus to read the metacontent.
4640 % o exception: return any errors or warnings in this structure.
4643 static MagickBooleanType ReadPixelCacheMetacontent(CacheInfo *cache_info,
4644 NexusInfo *nexus_info,ExceptionInfo *exception)
4657 register unsigned char
4663 if (cache_info->metacontent_extent == 0)
4664 return(MagickFalse);
4665 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4667 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4668 nexus_info->region.x;
4669 length=(MagickSizeType) nexus_info->region.width*
4670 cache_info->metacontent_extent;
4671 rows=nexus_info->region.height;
4673 q=(unsigned char *) nexus_info->metacontent;
4674 switch (cache_info->type)
4679 register unsigned char
4683 Read meta-content from memory.
4685 if ((cache_info->columns == nexus_info->region.width) &&
4686 (extent == (MagickSizeType) ((size_t) extent)))
4691 p=(unsigned char *) cache_info->metacontent+offset*
4692 cache_info->metacontent_extent;
4693 for (y=0; y < (ssize_t) rows; y++)
4695 (void) memcpy(q,p,(size_t) length);
4696 p+=cache_info->metacontent_extent*cache_info->columns;
4697 q+=cache_info->metacontent_extent*nexus_info->region.width;
4704 Read meta content from disk.
4706 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4708 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4709 cache_info->cache_filename);
4710 return(MagickFalse);
4712 if ((cache_info->columns == nexus_info->region.width) &&
4713 (extent <= MagickMaxBufferExtent))
4718 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4719 for (y=0; y < (ssize_t) rows; y++)
4721 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4722 cache_info->number_channels*sizeof(Quantum)+offset*
4723 cache_info->metacontent_extent,length,(unsigned char *) q);
4724 if ((MagickSizeType) count != length)
4726 offset+=cache_info->columns;
4727 q+=cache_info->metacontent_extent*nexus_info->region.width;
4729 if (y < (ssize_t) rows)
4731 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4732 cache_info->cache_filename);
4733 return(MagickFalse);
4740 if ((cache_info->debug != MagickFalse) &&
4741 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4742 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4743 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4744 nexus_info->region.width,(double) nexus_info->region.height,(double)
4745 nexus_info->region.x,(double) nexus_info->region.y);
4750 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4754 + R e a d P i x e l C a c h e P i x e l s %
4758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4760 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4763 % The format of the ReadPixelCachePixels() method is:
4765 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4766 % NexusInfo *nexus_info,ExceptionInfo *exception)
4768 % A description of each parameter follows:
4770 % o cache_info: the pixel cache.
4772 % o nexus_info: the cache nexus to read the pixels.
4774 % o exception: return any errors or warnings in this structure.
4777 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4778 NexusInfo *nexus_info,ExceptionInfo *exception)
4797 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
4799 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4800 nexus_info->region.x;
4801 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
4803 rows=nexus_info->region.height;
4805 q=nexus_info->pixels;
4806 switch (cache_info->type)
4815 Read pixels from memory.
4817 if ((cache_info->columns == nexus_info->region.width) &&
4818 (extent == (MagickSizeType) ((size_t) extent)))
4823 p=cache_info->pixels+offset*cache_info->number_channels;
4824 for (y=0; y < (ssize_t) rows; y++)
4826 (void) memcpy(q,p,(size_t) length);
4827 p+=cache_info->number_channels*cache_info->columns;
4828 q+=cache_info->number_channels*nexus_info->region.width;
4835 Read pixels from disk.
4837 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4839 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4840 cache_info->cache_filename);
4841 return(MagickFalse);
4843 if ((cache_info->columns == nexus_info->region.width) &&
4844 (extent <= MagickMaxBufferExtent))
4849 for (y=0; y < (ssize_t) rows; y++)
4851 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4852 cache_info->number_channels*sizeof(*q),length,(unsigned char *) q);
4853 if ((MagickSizeType) count != length)
4855 offset+=cache_info->columns;
4856 q+=cache_info->number_channels*nexus_info->region.width;
4858 if (y < (ssize_t) rows)
4860 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4861 cache_info->cache_filename);
4862 return(MagickFalse);
4869 if ((cache_info->debug != MagickFalse) &&
4870 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4871 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4872 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4873 nexus_info->region.width,(double) nexus_info->region.height,(double)
4874 nexus_info->region.x,(double) nexus_info->region.y);
4879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4883 + R e f e r e n c e P i x e l C a c h e %
4887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4889 % ReferencePixelCache() increments the reference count associated with the
4890 % pixel cache returning a pointer to the cache.
4892 % The format of the ReferencePixelCache method is:
4894 % Cache ReferencePixelCache(Cache cache_info)
4896 % A description of each parameter follows:
4898 % o cache_info: the pixel cache.
4901 MagickPrivate Cache ReferencePixelCache(Cache cache)
4906 assert(cache != (Cache *) NULL);
4907 cache_info=(CacheInfo *) cache;
4908 assert(cache_info->signature == MagickSignature);
4909 LockSemaphoreInfo(cache_info->semaphore);
4910 cache_info->reference_count++;
4911 UnlockSemaphoreInfo(cache_info->semaphore);
4916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4920 + S e t P i x e l C a c h e M e t h o d s %
4924 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4926 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4928 % The format of the SetPixelCacheMethods() method is:
4930 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4932 % A description of each parameter follows:
4934 % o cache: the pixel cache.
4936 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4939 MagickPrivate void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4944 GetOneAuthenticPixelFromHandler
4945 get_one_authentic_pixel_from_handler;
4947 GetOneVirtualPixelFromHandler
4948 get_one_virtual_pixel_from_handler;
4951 Set cache pixel methods.
4953 assert(cache != (Cache) NULL);
4954 assert(cache_methods != (CacheMethods *) NULL);
4955 cache_info=(CacheInfo *) cache;
4956 assert(cache_info->signature == MagickSignature);
4957 if (cache_info->debug != MagickFalse)
4958 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4959 cache_info->filename);
4960 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4961 cache_info->methods.get_virtual_pixel_handler=
4962 cache_methods->get_virtual_pixel_handler;
4963 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4964 cache_info->methods.destroy_pixel_handler=
4965 cache_methods->destroy_pixel_handler;
4966 if (cache_methods->get_virtual_metacontent_from_handler !=
4967 (GetVirtualMetacontentFromHandler) NULL)
4968 cache_info->methods.get_virtual_metacontent_from_handler=
4969 cache_methods->get_virtual_metacontent_from_handler;
4970 if (cache_methods->get_authentic_pixels_handler !=
4971 (GetAuthenticPixelsHandler) NULL)
4972 cache_info->methods.get_authentic_pixels_handler=
4973 cache_methods->get_authentic_pixels_handler;
4974 if (cache_methods->queue_authentic_pixels_handler !=
4975 (QueueAuthenticPixelsHandler) NULL)
4976 cache_info->methods.queue_authentic_pixels_handler=
4977 cache_methods->queue_authentic_pixels_handler;
4978 if (cache_methods->sync_authentic_pixels_handler !=
4979 (SyncAuthenticPixelsHandler) NULL)
4980 cache_info->methods.sync_authentic_pixels_handler=
4981 cache_methods->sync_authentic_pixels_handler;
4982 if (cache_methods->get_authentic_pixels_from_handler !=
4983 (GetAuthenticPixelsFromHandler) NULL)
4984 cache_info->methods.get_authentic_pixels_from_handler=
4985 cache_methods->get_authentic_pixels_from_handler;
4986 if (cache_methods->get_authentic_metacontent_from_handler !=
4987 (GetAuthenticMetacontentFromHandler) NULL)
4988 cache_info->methods.get_authentic_metacontent_from_handler=
4989 cache_methods->get_authentic_metacontent_from_handler;
4990 get_one_virtual_pixel_from_handler=
4991 cache_info->methods.get_one_virtual_pixel_from_handler;
4992 if (get_one_virtual_pixel_from_handler !=
4993 (GetOneVirtualPixelFromHandler) NULL)
4994 cache_info->methods.get_one_virtual_pixel_from_handler=
4995 cache_methods->get_one_virtual_pixel_from_handler;
4996 get_one_authentic_pixel_from_handler=
4997 cache_methods->get_one_authentic_pixel_from_handler;
4998 if (get_one_authentic_pixel_from_handler !=
4999 (GetOneAuthenticPixelFromHandler) NULL)
5000 cache_info->methods.get_one_authentic_pixel_from_handler=
5001 cache_methods->get_one_authentic_pixel_from_handler;
5005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5009 + S e t P i x e l C a c h e N e x u s P i x e l s %
5013 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5015 % SetPixelCacheNexusPixels() defines the region of the cache for the
5016 % specified cache nexus.
5018 % The format of the SetPixelCacheNexusPixels() method is:
5020 % Quantum SetPixelCacheNexusPixels(const Image *image,
5021 % const RectangleInfo *region,NexusInfo *nexus_info,
5022 % ExceptionInfo *exception)
5024 % A description of each parameter follows:
5026 % o image: the image.
5028 % o region: A pointer to the RectangleInfo structure that defines the
5029 % region of this particular cache nexus.
5031 % o nexus_info: the cache nexus to set.
5033 % o exception: return any errors or warnings in this structure.
5037 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
5038 NexusInfo *nexus_info,ExceptionInfo *exception)
5040 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
5041 return(MagickFalse);
5042 nexus_info->mapped=MagickFalse;
5043 nexus_info->cache=(Quantum *) AcquireQuantumMemory(1,(size_t)
5044 nexus_info->length);
5045 if (nexus_info->cache == (Quantum *) NULL)
5047 nexus_info->mapped=MagickTrue;
5048 nexus_info->cache=(Quantum *) MapBlob(-1,IOMode,0,(size_t)
5049 nexus_info->length);
5051 if (nexus_info->cache == (Quantum *) NULL)
5053 (void) ThrowMagickException(exception,GetMagickModule(),
5054 ResourceLimitError,"MemoryAllocationFailed","`%s'",
5055 cache_info->filename);
5056 return(MagickFalse);
5061 static Quantum *SetPixelCacheNexusPixels(const Image *image,
5062 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5074 cache_info=(CacheInfo *) image->cache;
5075 assert(cache_info->signature == MagickSignature);
5076 if (cache_info->type == UndefinedCache)
5077 return((Quantum *) NULL);
5078 nexus_info->region=(*region);
5079 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5080 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5086 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5087 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5088 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5089 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5090 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5091 ((nexus_info->region.width == cache_info->columns) ||
5092 ((nexus_info->region.width % cache_info->columns) == 0)))))
5098 Pixels are accessed directly from memory.
5100 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5101 nexus_info->region.x;
5102 nexus_info->pixels=cache_info->pixels+cache_info->number_channels*
5104 nexus_info->metacontent=(void *) NULL;
5105 if (cache_info->metacontent_extent != 0)
5106 nexus_info->metacontent=(unsigned char *) cache_info->metacontent+
5107 offset*cache_info->metacontent_extent;
5108 return(nexus_info->pixels);
5112 Pixels are stored in a cache region until they are synced to the cache.
5114 number_pixels=(MagickSizeType) nexus_info->region.width*
5115 nexus_info->region.height;
5116 length=number_pixels*cache_info->number_channels*sizeof(Quantum);
5117 if (cache_info->metacontent_extent != 0)
5118 length+=number_pixels*cache_info->metacontent_extent;
5119 if (nexus_info->cache == (Quantum *) NULL)
5121 nexus_info->length=length;
5122 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5123 if (status == MagickFalse)
5125 nexus_info->length=0;
5126 return((Quantum *) NULL);
5130 if (nexus_info->length != length)
5132 RelinquishCacheNexusPixels(nexus_info);
5133 nexus_info->length=length;
5134 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5135 if (status == MagickFalse)
5137 nexus_info->length=0;
5138 return((Quantum *) NULL);
5141 nexus_info->pixels=nexus_info->cache;
5142 nexus_info->metacontent=(void *) NULL;
5143 if (cache_info->metacontent_extent != 0)
5144 nexus_info->metacontent=(void *) (nexus_info->pixels+number_pixels*
5145 cache_info->number_channels);
5146 return(nexus_info->pixels);
5150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5154 % 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 %
5158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5160 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5161 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5162 % access that is outside the boundaries of the image cache.
5164 % The format of the SetPixelCacheVirtualMethod() method is:
5166 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5167 % const VirtualPixelMethod virtual_pixel_method)
5169 % A description of each parameter follows:
5171 % o image: the image.
5173 % o virtual_pixel_method: choose the type of virtual pixel.
5176 MagickPrivate VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5177 const VirtualPixelMethod virtual_pixel_method)
5185 assert(image != (Image *) NULL);
5186 assert(image->signature == MagickSignature);
5187 if (image->debug != MagickFalse)
5188 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5189 assert(image->cache != (Cache) NULL);
5190 cache_info=(CacheInfo *) image->cache;
5191 assert(cache_info->signature == MagickSignature);
5192 method=cache_info->virtual_pixel_method;
5193 cache_info->virtual_pixel_method=virtual_pixel_method;
5198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5202 + 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 %
5206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5208 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5209 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5210 % is synced, otherwise MagickFalse.
5212 % The format of the SyncAuthenticPixelCacheNexus() method is:
5214 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5215 % NexusInfo *nexus_info,ExceptionInfo *exception)
5217 % A description of each parameter follows:
5219 % o image: the image.
5221 % o nexus_info: the cache nexus to sync.
5223 % o exception: return any errors or warnings in this structure.
5226 MagickPrivate MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5227 NexusInfo *nexus_info,ExceptionInfo *exception)
5236 Transfer pixels to the cache.
5238 assert(image != (Image *) NULL);
5239 assert(image->signature == MagickSignature);
5240 if (image->cache == (Cache) NULL)
5241 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5242 cache_info=(CacheInfo *) image->cache;
5243 assert(cache_info->signature == MagickSignature);
5244 if (cache_info->type == UndefinedCache)
5245 return(MagickFalse);
5246 if ((image->clip_mask != (Image *) NULL) &&
5247 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5248 return(MagickFalse);
5249 if ((image->mask != (Image *) NULL) &&
5250 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5251 return(MagickFalse);
5252 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5254 assert(cache_info->signature == MagickSignature);
5255 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5256 if ((cache_info->metacontent_extent != 0) &&
5257 (WritePixelCacheMetacontent(cache_info,nexus_info,exception) == MagickFalse))
5258 return(MagickFalse);
5263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5267 + S y n c A u t h e n t i c P i x e l C a c h e %
5271 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5273 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5274 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5275 % otherwise MagickFalse.
5277 % The format of the SyncAuthenticPixelsCache() method is:
5279 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5280 % ExceptionInfo *exception)
5282 % A description of each parameter follows:
5284 % o image: the image.
5286 % o exception: return any errors or warnings in this structure.
5289 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5290 ExceptionInfo *exception)
5296 id = GetOpenMPThreadId();
5301 assert(image != (Image *) NULL);
5302 assert(image->signature == MagickSignature);
5303 assert(image->cache != (Cache) NULL);
5304 cache_info=(CacheInfo *) image->cache;
5305 assert(cache_info->signature == MagickSignature);
5306 assert(id < (int) cache_info->number_threads);
5307 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5317 % S y n c A u t h e n t i c P i x e l s %
5321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5323 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5324 % The method returns MagickTrue if the pixel region is flushed, otherwise
5327 % The format of the SyncAuthenticPixels() method is:
5329 % MagickBooleanType SyncAuthenticPixels(Image *image,
5330 % ExceptionInfo *exception)
5332 % A description of each parameter follows:
5334 % o image: the image.
5336 % o exception: return any errors or warnings in this structure.
5339 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5340 ExceptionInfo *exception)
5346 id = GetOpenMPThreadId();
5351 assert(image != (Image *) NULL);
5352 assert(image->signature == MagickSignature);
5353 assert(image->cache != (Cache) NULL);
5354 cache_info=(CacheInfo *) image->cache;
5355 assert(cache_info->signature == MagickSignature);
5356 if (cache_info->methods.sync_authentic_pixels_handler !=
5357 (SyncAuthenticPixelsHandler) NULL)
5359 status=cache_info->methods.sync_authentic_pixels_handler(image,
5363 assert(id < (int) cache_info->number_threads);
5364 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5374 + S y n c I m a g e P i x e l C a c h e %
5378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5380 % SyncImagePixelCache() saves the image pixels to the in-memory or disk cache.
5381 % The method returns MagickTrue if the pixel region is flushed, otherwise
5384 % The format of the SyncImagePixelCache() method is:
5386 % MagickBooleanType SyncImagePixelCache(Image *image,
5387 % ExceptionInfo *exception)
5389 % A description of each parameter follows:
5391 % o image: the image.
5393 % o exception: return any errors or warnings in this structure.
5396 MagickPrivate MagickBooleanType SyncImagePixelCache(Image *image,
5397 ExceptionInfo *exception)
5402 assert(image != (Image *) NULL);
5403 assert(exception != (ExceptionInfo *) NULL);
5404 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5405 return(cache_info == (CacheInfo *) NULL ? MagickFalse : MagickTrue);
5409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5413 + 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 %
5417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5419 % WritePixelCacheMetacontent() writes the meta-content to the specified region
5420 % of the pixel cache.
5422 % The format of the WritePixelCacheMetacontent() method is:
5424 % MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5425 % NexusInfo *nexus_info,ExceptionInfo *exception)
5427 % A description of each parameter follows:
5429 % o cache_info: the pixel cache.
5431 % o nexus_info: the cache nexus to write the meta-content.
5433 % o exception: return any errors or warnings in this structure.
5436 static MagickBooleanType WritePixelCacheMetacontent(CacheInfo *cache_info,
5437 NexusInfo *nexus_info,ExceptionInfo *exception)
5447 register const unsigned char
5456 if (cache_info->metacontent_extent == 0)
5457 return(MagickFalse);
5458 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5460 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5461 nexus_info->region.x;
5462 length=(MagickSizeType) nexus_info->region.width*
5463 cache_info->metacontent_extent;
5464 rows=nexus_info->region.height;
5465 extent=(MagickSizeType) length*rows;
5466 p=(unsigned char *) nexus_info->metacontent;
5467 switch (cache_info->type)
5472 register unsigned char
5476 Write associated pixels to memory.
5478 if ((cache_info->columns == nexus_info->region.width) &&
5479 (extent == (MagickSizeType) ((size_t) extent)))
5484 q=(unsigned char *) cache_info->metacontent+offset*
5485 cache_info->metacontent_extent;
5486 for (y=0; y < (ssize_t) rows; y++)
5488 (void) memcpy(q,p,(size_t) length);
5489 p+=nexus_info->region.width*cache_info->metacontent_extent;
5490 q+=cache_info->columns*cache_info->metacontent_extent;
5497 Write associated pixels to disk.
5499 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5501 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5502 cache_info->cache_filename);
5503 return(MagickFalse);
5505 if ((cache_info->columns == nexus_info->region.width) &&
5506 (extent <= MagickMaxBufferExtent))
5511 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5512 for (y=0; y < (ssize_t) rows; y++)
5514 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5515 cache_info->number_channels*sizeof(Quantum)+offset*
5516 cache_info->metacontent_extent,length,(const unsigned char *) p);
5517 if ((MagickSizeType) count != length)
5519 p+=nexus_info->region.width*cache_info->metacontent_extent;
5520 offset+=cache_info->columns;
5522 if (y < (ssize_t) rows)
5524 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5525 cache_info->cache_filename);
5526 return(MagickFalse);
5533 if ((cache_info->debug != MagickFalse) &&
5534 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5535 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5536 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5537 nexus_info->region.width,(double) nexus_info->region.height,(double)
5538 nexus_info->region.x,(double) nexus_info->region.y);
5543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5547 + W r i t e C a c h e P i x e l s %
5551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5553 % WritePixelCachePixels() writes image pixels to the specified region of the
5556 % The format of the WritePixelCachePixels() method is:
5558 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5559 % NexusInfo *nexus_info,ExceptionInfo *exception)
5561 % A description of each parameter follows:
5563 % o cache_info: the pixel cache.
5565 % o nexus_info: the cache nexus to write the pixels.
5567 % o exception: return any errors or warnings in this structure.
5570 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5571 NexusInfo *nexus_info,ExceptionInfo *exception)
5581 register const Quantum
5590 if (IsPixelAuthentic(cache_info,nexus_info) != MagickFalse)
5592 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5593 nexus_info->region.x;
5594 length=(MagickSizeType) nexus_info->region.width*cache_info->number_channels*
5596 rows=nexus_info->region.height;
5598 p=nexus_info->pixels;
5599 switch (cache_info->type)
5608 Write pixels to memory.
5610 if ((cache_info->columns == nexus_info->region.width) &&
5611 (extent == (MagickSizeType) ((size_t) extent)))
5616 q=cache_info->pixels+offset*cache_info->number_channels;
5617 for (y=0; y < (ssize_t) rows; y++)
5619 (void) memcpy(q,p,(size_t) length);
5620 p+=nexus_info->region.width*cache_info->number_channels;
5621 q+=cache_info->columns*cache_info->number_channels;
5628 Write pixels to disk.
5630 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5632 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5633 cache_info->cache_filename);
5634 return(MagickFalse);
5636 if ((cache_info->columns == nexus_info->region.width) &&
5637 (extent <= MagickMaxBufferExtent))
5642 for (y=0; y < (ssize_t) rows; y++)
5644 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5645 cache_info->number_channels*sizeof(*p),length,(const unsigned char *)
5647 if ((MagickSizeType) count != length)
5649 p+=nexus_info->region.width*cache_info->number_channels;
5650 offset+=cache_info->columns;
5652 if (y < (ssize_t) rows)
5654 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5655 cache_info->cache_filename);
5656 return(MagickFalse);
5663 if ((cache_info->debug != MagickFalse) &&
5664 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5665 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5666 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5667 nexus_info->region.width,(double) nexus_info->region.height,(double)
5668 nexus_info->region.x,(double) nexus_info->region.y);