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-2009 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 "magick/studio.h"
44 #include "magick/blob.h"
45 #include "magick/blob-private.h"
46 #include "magick/cache.h"
47 #include "magick/cache-private.h"
48 #include "magick/color-private.h"
49 #include "magick/composite-private.h"
50 #include "magick/exception.h"
51 #include "magick/exception-private.h"
52 #include "magick/list.h"
53 #include "magick/log.h"
54 #include "magick/magick.h"
55 #include "magick/memory_.h"
56 #include "magick/pixel-private.h"
57 #include "magick/quantum.h"
58 #include "magick/random_.h"
59 #include "magick/resource_.h"
60 #include "magick/semaphore.h"
61 #include "magick/splay-tree.h"
62 #include "magick/string_.h"
63 #include "magick/thread-private.h"
64 #include "magick/utility.h"
65 #if defined(MAGICKCORE_ZLIB_DELEGATE)
72 typedef struct _MagickModulo
102 Forward declarations.
104 #if defined(__cplusplus) || defined(c_plusplus)
108 static const IndexPacket
109 *GetVirtualIndexesFromCache(const Image *);
111 static const PixelPacket
112 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const long,
113 const long,const unsigned long,const unsigned long,ExceptionInfo *),
114 *GetVirtualPixelsCache(const Image *);
116 static MagickBooleanType
117 GetOneAuthenticPixelFromCache(Image *,const long,const long,PixelPacket *,
119 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
120 const long,const long,PixelPacket *,ExceptionInfo *),
121 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
122 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
123 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
124 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
125 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
126 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
129 *GetAuthenticPixelsCache(Image *,const long,const long,const unsigned long,
130 const unsigned long,ExceptionInfo *),
131 *QueueAuthenticPixelsCache(Image *,const long,const long,const unsigned long,
132 const unsigned long,ExceptionInfo *),
133 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
136 #if defined(__cplusplus) || defined(c_plusplus)
143 static volatile MagickBooleanType
144 instantiate_cache = MagickFalse;
147 *cache_semaphore = (SemaphoreInfo *) NULL;
150 *cache_resources = (SplayTreeInfo *) NULL;
156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 + A c q u i r e P i x e l C a c h e %
164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166 % AcquirePixelCache() acquires a pixel cache.
168 % The format of the AcquirePixelCache() method is:
170 % Cache AcquirePixelCache(const unsigned long number_threads)
172 % A description of each parameter follows:
174 % o number_threads: the number of nexus threads.
177 MagickExport Cache AcquirePixelCache(const unsigned long number_threads)
182 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
183 if (cache_info == (CacheInfo *) NULL)
184 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
185 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
186 cache_info->type=UndefinedCache;
187 cache_info->mode=IOMode;
188 cache_info->colorspace=RGBColorspace;
189 cache_info->file=(-1);
190 cache_info->id=GetMagickThreadId();
191 cache_info->number_threads=number_threads;
192 if (number_threads == 0)
193 cache_info->number_threads=GetOpenMPMaximumThreads();
194 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
195 if (cache_info->nexus_info == (NexusInfo **) NULL)
196 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
197 GetPixelCacheMethods(&cache_info->methods);
198 cache_info->reference_count=1;
199 cache_info->semaphore=AllocateSemaphoreInfo();
200 cache_info->disk_semaphore=AllocateSemaphoreInfo();
201 cache_info->debug=IsEventLogging();
202 cache_info->signature=MagickSignature;
203 if ((cache_resources == (SplayTreeInfo *) NULL) &&
204 (instantiate_cache == MagickFalse))
206 if (cache_semaphore == (SemaphoreInfo *) NULL)
207 AcquireSemaphoreInfo(&cache_semaphore);
208 (void) LockSemaphoreInfo(cache_semaphore);
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
212 cache_resources=NewSplayTree((int (*)(const void *,const void *))
213 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
214 instantiate_cache=MagickTrue;
216 (void) UnlockSemaphoreInfo(cache_semaphore);
218 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
219 return((Cache ) cache_info);
223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
227 % A c q u i r e P i x e l C a c h e N e x u s %
231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
235 % The format of the AcquirePixelCacheNexus method is:
237 % NexusInfo **AcquirePixelCacheNexus(const unsigned long number_threads)
239 % A description of each parameter follows:
241 % o number_threads: the number of nexus threads.
244 MagickExport NexusInfo **AcquirePixelCacheNexus(
245 const unsigned long number_threads)
253 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
254 sizeof(*nexus_info));
255 if (nexus_info == (NexusInfo **) NULL)
256 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
257 for (i=0; i < (long) number_threads; i++)
259 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
260 if (nexus_info[i] == (NexusInfo *) NULL)
261 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
262 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
263 nexus_info[i]->signature=MagickSignature;
269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273 + C a c h e C o m p o n e n t G e n e s i s %
277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279 % CacheComponentGenesis() instantiates the cache component.
281 % The format of the CacheComponentGenesis method is:
283 % MagickBooleanType CacheComponentGenesis(void)
286 MagickExport MagickBooleanType CacheComponentGenesis(void)
288 AcquireSemaphoreInfo(&cache_semaphore);
293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
297 + C a c h e C o m p o n e n t T e r m i n u s %
301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
303 % CacheComponentTerminus() destroys the cache component.
305 % The format of the CacheComponentTerminus() method is:
307 % CacheComponentTerminus(void)
310 MagickExport void CacheComponentTerminus(void)
312 if (cache_semaphore == (SemaphoreInfo *) NULL)
313 AcquireSemaphoreInfo(&cache_semaphore);
314 (void) LockSemaphoreInfo(cache_semaphore);
315 if (cache_resources != (SplayTreeInfo *) NULL)
316 cache_resources=DestroySplayTree(cache_resources);
317 instantiate_cache=MagickFalse;
318 (void) UnlockSemaphoreInfo(cache_semaphore);
319 DestroySemaphoreInfo(&cache_semaphore);
323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327 + C l i p P i x e l C a c h e N e x u s %
331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333 % ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
334 % mask. The method returns MagickTrue if the pixel region is clipped,
335 % otherwise MagickFalse.
337 % The format of the ClipPixelCacheNexus() method is:
339 % MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
340 % ExceptionInfo *exception)
342 % A description of each parameter follows:
344 % o image: the image.
346 % o nexus_info: the cache nexus to clip.
348 % o exception: return any errors or warnings in this structure.
351 static MagickBooleanType ClipPixelCacheNexus(Image *image,
352 NexusInfo *nexus_info,ExceptionInfo *exception)
364 register const PixelPacket
368 *__restrict nexus_indexes,
381 if (image->debug != MagickFalse)
382 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
383 if (image->clip_mask == (Image *) NULL)
385 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
386 if (cache_info == (Cache) NULL)
388 image_nexus=AcquirePixelCacheNexus(1);
389 clip_nexus=AcquirePixelCacheNexus(1);
390 if ((image_nexus == (NexusInfo **) NULL) ||
391 (clip_nexus == (NexusInfo **) NULL))
392 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
393 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
394 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
396 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
397 q=nexus_info->pixels;
398 nexus_indexes=nexus_info->indexes;
399 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
400 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
401 nexus_info->region.height,clip_nexus[0],exception);
402 number_pixels=(MagickSizeType) nexus_info->region.width*
403 nexus_info->region.height;
404 for (i=0; i < (long) number_pixels; i++)
406 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
408 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
413 q->opacity=p->opacity;
414 if (cache_info->active_index_channel != MagickFalse)
415 nexus_indexes[i]=indexes[i];
421 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
422 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
423 if (i < (long) number_pixels)
429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
433 + C l o n e P i x e l C a c h e %
437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439 % ClonePixelCache() clones a pixel cache.
441 % The format of the ClonePixelCache() method is:
443 % Cache ClonePixelCache(const Cache cache)
445 % A description of each parameter follows:
447 % o cache: the pixel cache.
450 MagickExport Cache ClonePixelCache(const Cache cache)
458 assert(cache != (const Cache) NULL);
459 cache_info=(const CacheInfo *) cache;
460 assert(cache_info->signature == MagickSignature);
461 if (cache_info->debug != MagickFalse)
462 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
463 cache_info->filename);
464 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
465 if (clone_info == (Cache) NULL)
466 return((Cache) NULL);
467 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
468 return((Cache ) clone_info);
472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
476 + C l o n e P i x e l C a c h e N e x u s %
480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
482 % ClonePixelCacheNexus() clones the source cache nexus to the destination
485 % The format of the ClonePixelCacheNexus() method is:
487 % MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
488 % CacheInfo *source,ExceptionInfo *exception)
490 % A description of each parameter follows:
492 % o destination: the destination cache nexus.
494 % o source: the source cache nexus.
496 % o exception: return any errors or warnings in this structure.
500 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
501 NexusInfo *nexus_info,ExceptionInfo *exception)
503 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
505 nexus_info->mapped=MagickFalse;
506 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
508 if (nexus_info->cache == (PixelPacket *) NULL)
510 nexus_info->mapped=MagickTrue;
511 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
514 if (nexus_info->cache == (PixelPacket *) NULL)
516 (void) ThrowMagickException(exception,GetMagickModule(),
517 ResourceLimitError,"MemoryAllocationFailed","`%s'",
518 cache_info->filename);
524 static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
525 CacheInfo *source,ExceptionInfo *exception)
536 register const NexusInfo
543 for (i=0; i < (long) source->number_threads; i++)
545 p=source->nexus_info[i];
546 q=destination->nexus_info[i];
552 q->indexes=p->indexes;
553 if (p->cache != (PixelPacket *) NULL)
555 status=AcquireCacheNexusPixels(source,q,exception);
556 if (status != MagickFalse)
558 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
560 q->indexes=(IndexPacket *) NULL;
561 number_pixels=(MagickSizeType) q->region.width*q->region.height;
562 if (p->indexes != (IndexPacket *) NULL)
563 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
575 + C l o n e P i x e l C a c h e P i x e l s %
579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
580 % ClonePixelCachePixels() clones the source pixel cache to the destination
583 % The format of the ClonePixelCachePixels() method is:
585 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
586 % CacheInfo *source_info,ExceptionInfo *exception)
588 % A description of each parameter follows:
590 % o cache_info: the pixel cache.
592 % o source_info: the source pixel cache.
594 % o exception: return any errors or warnings in this structure.
598 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
603 (void) LockSemaphoreInfo(cache_info->disk_semaphore);
604 status=close(cache_info->file);
605 cache_info->file=(-1);
606 RelinquishMagickResource(FileResource,1);
607 (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
608 return(status == -1 ? MagickFalse : MagickTrue);
611 static void LimitPixelCacheDescriptors(void)
618 Limit # of open file descriptors.
620 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
622 (void) LockSemaphoreInfo(cache_semaphore);
623 if (cache_resources == (SplayTreeInfo *) NULL)
625 (void) UnlockSemaphoreInfo(cache_semaphore);
628 ResetSplayTreeIterator(cache_resources);
629 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
630 while (p != (CacheInfo *) NULL)
632 if ((p->type == DiskCache) && (p->file != -1))
634 if (IsMagickThreadEqual(p->id) != MagickFalse)
637 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
639 for (q=p; p != (CacheInfo *) NULL; )
641 if ((p->type == DiskCache) && (p->file != -1) &&
642 (p->timestamp < q->timestamp))
644 if (IsMagickThreadEqual(p->id) != MagickFalse)
647 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
649 if (q != (CacheInfo *) NULL)
650 (void) ClosePixelCacheOnDisk(q); /* relinquish least recently used cache */
651 (void) UnlockSemaphoreInfo(cache_semaphore);
654 static inline MagickSizeType MagickMax(const MagickSizeType x,
655 const MagickSizeType y)
662 static inline MagickSizeType MagickMin(const MagickSizeType x,
663 const MagickSizeType y)
670 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
677 Open pixel cache on disk.
679 (void) LockSemaphoreInfo(cache_info->disk_semaphore);
680 if (cache_info->file != -1)
682 (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
683 return(MagickTrue); /* cache already open */
685 LimitPixelCacheDescriptors();
686 if (*cache_info->cache_filename == '\0')
687 file=AcquireUniqueFileResource(cache_info->cache_filename);
693 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
698 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
701 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
707 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
710 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
716 (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
719 (void) AcquireMagickResource(FileResource,1);
720 cache_info->file=file;
721 cache_info->timestamp=time(0);
722 (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
726 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
727 const MagickOffsetType offset,const MagickSizeType length,
728 unsigned char *__restrict buffer)
730 register MagickOffsetType
736 #if !defined(MAGICKCORE_HAVE_PREAD)
737 (void) LockSemaphoreInfo(cache_info->disk_semaphore);
738 cache_info->timestamp=time(0);
739 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
741 (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
742 return((MagickOffsetType) -1);
746 for (i=0; i < (MagickOffsetType) length; i+=count)
748 #if !defined(MAGICKCORE_HAVE_PREAD)
749 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
750 (MagickSizeType) SSIZE_MAX));
752 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
753 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
764 #if !defined(MAGICKCORE_HAVE_PREAD)
765 (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
770 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
771 const MagickOffsetType offset,const MagickSizeType length,
772 const unsigned char *__restrict buffer)
774 register MagickOffsetType
780 #if !defined(MAGICKCORE_HAVE_PWRITE)
781 (void) LockSemaphoreInfo(cache_info->disk_semaphore);
782 cache_info->timestamp=time(0);
783 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
785 (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
786 return((MagickOffsetType) -1);
790 for (i=0; i < (MagickOffsetType) length; i+=count)
792 #if !defined(MAGICKCORE_HAVE_PWRITE)
793 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
794 (MagickSizeType) SSIZE_MAX));
796 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
797 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
808 #if !defined(MAGICKCORE_HAVE_PWRITE)
809 (void) UnlockSemaphoreInfo(cache_info->disk_semaphore);
814 static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
815 CacheInfo *cache_info,ExceptionInfo *exception)
835 if (cache_info->debug != MagickFalse)
836 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
837 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
839 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
840 clone_info->cache_filename);
843 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
845 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
846 cache_info->cache_filename);
849 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
850 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
851 if ((clone_info->active_index_channel != MagickFalse) &&
852 (cache_info->active_index_channel != MagickFalse))
860 length=MagickMax(clone_info->columns,cache_info->columns)*
862 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
863 if (indexes == (IndexPacket *) NULL)
865 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
866 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
869 (void) ResetMagickMemory(indexes,0,(size_t) length);
870 length=columns*sizeof(*indexes);
871 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
872 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
873 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
874 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
875 for (y=0; y < (long) rows; y++)
877 source_offset-=cache_info->columns*sizeof(*indexes);
878 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
879 length,(unsigned char *) indexes);
880 if ((MagickSizeType) count != length)
882 offset-=clone_info->columns*sizeof(*indexes);
883 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
884 (unsigned char *) indexes);
885 if ((MagickSizeType) count != length)
890 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
891 ThrowFileException(exception,CacheError,"UnableToCloneCache",
892 cache_info->cache_filename);
895 if (clone_info->columns > cache_info->columns)
897 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
898 (void) ResetMagickMemory(indexes,0,(size_t) length);
899 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
900 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
901 for (y=0; y < (long) rows; y++)
903 offset-=clone_info->columns*sizeof(*indexes);
904 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
905 length,(unsigned char *) indexes);
906 if ((MagickSizeType) count != length)
911 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
912 ThrowFileException(exception,CacheError,"UnableToCloneCache",
913 cache_info->cache_filename);
917 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
922 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
923 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
924 if (pixels == (PixelPacket *) NULL)
926 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
927 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
930 (void) ResetMagickMemory(pixels,0,(size_t) length);
931 length=columns*sizeof(*pixels);
932 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
933 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
934 for (y=0; y < (long) rows; y++)
936 source_offset-=cache_info->columns*sizeof(*pixels);
937 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
938 length,(unsigned char *) pixels);
939 if ((MagickSizeType) count != length)
941 offset-=clone_info->columns*sizeof(*pixels);
942 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
943 (unsigned char *) pixels);
944 if ((MagickSizeType) count != length)
949 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
950 ThrowFileException(exception,CacheError,"UnableToCloneCache",
951 cache_info->cache_filename);
954 if (clone_info->columns > cache_info->columns)
956 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
958 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
959 (void) ResetMagickMemory(pixels,0,(size_t) length);
960 for (y=0; y < (long) rows; y++)
962 offset-=clone_info->columns*sizeof(*pixels);
963 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
964 (unsigned char *) pixels);
965 if ((MagickSizeType) count != length)
970 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
971 ThrowFileException(exception,CacheError,"UnableToCloneCache",
972 cache_info->cache_filename);
976 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
980 static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
981 CacheInfo *cache_info,ExceptionInfo *exception)
1001 if (cache_info->debug != MagickFalse)
1002 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1003 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1005 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1009 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1010 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1011 if ((clone_info->active_index_channel != MagickFalse) &&
1012 (cache_info->active_index_channel != MagickFalse))
1014 register IndexPacket
1019 Clone cache indexes.
1021 length=MagickMax(clone_info->columns,cache_info->columns)*
1023 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1024 if (indexes == (IndexPacket *) NULL)
1026 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1027 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1028 return(MagickFalse);
1030 (void) ResetMagickMemory(indexes,0,(size_t) length);
1031 length=columns*sizeof(IndexPacket);
1032 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1033 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1034 q=clone_info->indexes+clone_info->columns*rows;
1035 for (y=0; y < (long) rows; y++)
1037 offset-=cache_info->columns*sizeof(IndexPacket);
1038 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1039 length,(unsigned char *) indexes);
1040 if ((MagickSizeType) count != length)
1042 q-=clone_info->columns;
1043 (void) CopyMagickMemory(q,indexes,(size_t) length);
1044 if ((MagickSizeType) count != length)
1047 if (y < (long) rows)
1049 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1050 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1051 cache_info->cache_filename);
1052 return(MagickFalse);
1054 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1059 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1060 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1061 if (pixels == (PixelPacket *) NULL)
1063 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1064 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1065 return(MagickFalse);
1067 (void) ResetMagickMemory(pixels,0,(size_t) length);
1068 length=columns*sizeof(*pixels);
1069 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1070 q=clone_info->pixels+clone_info->columns*rows;
1071 for (y=0; y < (long) rows; y++)
1073 offset-=cache_info->columns*sizeof(*pixels);
1074 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1075 (unsigned char *) pixels);
1076 if ((MagickSizeType) count != length)
1078 q-=clone_info->columns;
1079 (void) CopyMagickMemory(q,pixels,(size_t) length);
1081 if (y < (long) rows)
1083 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1084 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1085 cache_info->cache_filename);
1086 return(MagickFalse);
1088 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1092 static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1093 CacheInfo *cache_info,ExceptionInfo *exception)
1105 register PixelPacket
1113 if (cache_info->debug != MagickFalse)
1114 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1115 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1117 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1118 clone_info->cache_filename);
1119 return(MagickFalse);
1121 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1122 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1123 if ((clone_info->active_index_channel != MagickFalse) &&
1124 (cache_info->active_index_channel != MagickFalse))
1126 register IndexPacket
1131 Clone cache indexes.
1133 length=MagickMax(clone_info->columns,cache_info->columns)*
1135 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1136 if (indexes == (IndexPacket *) NULL)
1138 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1139 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1140 return(MagickFalse);
1142 (void) ResetMagickMemory(indexes,0,(size_t) length);
1143 length=columns*sizeof(*indexes);
1144 p=cache_info->indexes+cache_info->columns*rows;
1145 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1146 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
1147 for (y=0; y < (long) rows; y++)
1149 p-=cache_info->columns;
1150 (void) CopyMagickMemory(indexes,p,(size_t) length);
1151 offset-=clone_info->columns*sizeof(*indexes);
1152 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1153 (unsigned char *) indexes);
1154 if ((MagickSizeType) count != length)
1157 if (y < (long) rows)
1159 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1160 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1161 cache_info->cache_filename);
1162 return(MagickFalse);
1164 if (clone_info->columns > cache_info->columns)
1166 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1167 (void) ResetMagickMemory(indexes,0,(size_t) length);
1168 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1169 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
1170 for (y=0; y < (long) rows; y++)
1172 offset-=clone_info->columns*sizeof(*indexes);
1173 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1174 length,(unsigned char *) indexes);
1175 if ((MagickSizeType) count != length)
1178 if (y < (long) rows)
1180 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1181 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1182 cache_info->cache_filename);
1183 return(MagickFalse);
1186 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1191 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1192 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1193 if (pixels == (PixelPacket *) NULL)
1195 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1196 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1197 return(MagickFalse);
1199 (void) ResetMagickMemory(pixels,0,(size_t) length);
1200 length=columns*sizeof(*pixels);
1201 p=cache_info->pixels+cache_info->columns*rows;
1202 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
1203 for (y=0; y < (long) rows; y++)
1205 p-=cache_info->columns;
1206 (void) CopyMagickMemory(pixels,p,(size_t) length);
1207 offset-=clone_info->columns*sizeof(*pixels);
1208 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1209 (unsigned char *) pixels);
1210 if ((MagickSizeType) count != length)
1213 if (y < (long) rows)
1215 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1216 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1217 cache_info->cache_filename);
1218 return(MagickFalse);
1220 if (clone_info->columns > cache_info->columns)
1222 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1224 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1225 (void) ResetMagickMemory(pixels,0,(size_t) length);
1226 for (y=0; y < (long) rows; y++)
1228 offset-=clone_info->columns*sizeof(*pixels);
1229 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1230 (unsigned char *) pixels);
1231 if ((MagickSizeType) count != length)
1234 if (y < (long) rows)
1236 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1237 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1238 cache_info->cache_filename);
1239 return(MagickFalse);
1242 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1246 static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1247 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1252 register PixelPacket
1254 *__restrict source_pixels;
1263 if (cache_info->debug != MagickFalse)
1264 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
1265 columns=(unsigned long) MagickMin(clone_info->columns,cache_info->columns);
1266 rows=(unsigned long) MagickMin(clone_info->rows,cache_info->rows);
1267 if ((clone_info->active_index_channel != MagickFalse) &&
1268 (cache_info->active_index_channel != MagickFalse))
1270 register IndexPacket
1275 Clone cache indexes.
1277 length=columns*sizeof(*indexes);
1278 if (clone_info->columns == cache_info->columns)
1279 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1283 source_indexes=cache_info->indexes+cache_info->columns*rows;
1284 indexes=clone_info->indexes+clone_info->columns*rows;
1285 for (y=0; y < (long) rows; y++)
1287 source_indexes-=cache_info->columns;
1288 indexes-=clone_info->columns;
1289 (void) CopyMagickMemory(indexes,source_indexes,length);
1291 if (clone_info->columns > cache_info->columns)
1293 length=(clone_info->columns-cache_info->columns)*
1295 indexes=clone_info->indexes+clone_info->columns*rows+
1296 cache_info->columns;
1297 for (y=0; y < (long) rows; y++)
1299 indexes-=clone_info->columns;
1300 (void) ResetMagickMemory(indexes,0,length);
1308 length=columns*sizeof(*pixels);
1309 if (clone_info->columns == cache_info->columns)
1310 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1313 source_pixels=cache_info->pixels+cache_info->columns*rows;
1314 pixels=clone_info->pixels+clone_info->columns*rows;
1315 for (y=0; y < (long) rows; y++)
1317 source_pixels-=cache_info->columns;
1318 pixels-=clone_info->columns;
1319 (void) CopyMagickMemory(pixels,source_pixels,length);
1321 if (clone_info->columns > cache_info->columns)
1323 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1324 pixels=clone_info->pixels+clone_info->columns*rows+
1325 cache_info->columns;
1326 for (y=0; y < (long) rows; y++)
1328 pixels-=clone_info->columns;
1329 (void) ResetMagickMemory(pixels,0,length);
1336 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1337 CacheInfo *cache_info,ExceptionInfo *exception)
1339 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1340 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1341 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1342 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1343 if (cache_info->type == DiskCache)
1344 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1345 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353 + C l o n e P i x e l C a c h e M e t h o d s %
1357 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1362 % The format of the ClonePixelCacheMethods() method is:
1364 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1366 % A description of each parameter follows:
1368 % o clone: Specifies a pointer to a Cache structure.
1370 % o cache: the pixel cache.
1373 MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1379 assert(clone != (Cache) NULL);
1380 source_info=(CacheInfo *) clone;
1381 assert(source_info->signature == MagickSignature);
1382 if (source_info->debug != MagickFalse)
1383 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1384 source_info->filename);
1385 assert(cache != (Cache) NULL);
1386 cache_info=(CacheInfo *) cache;
1387 assert(cache_info->signature == MagickSignature);
1388 source_info->methods=cache_info->methods;
1392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1396 + D e s t r o y I m a g e P i x e l C a c h e %
1400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1404 % The format of the DestroyImagePixelCache() method is:
1406 % void DestroyImagePixelCache(Image *image)
1408 % A description of each parameter follows:
1410 % o image: the image.
1413 static void DestroyImagePixelCache(Image *image)
1415 assert(image != (Image *) NULL);
1416 assert(image->signature == MagickSignature);
1417 if (image->debug != MagickFalse)
1418 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1419 if (image->cache == (void *) NULL)
1421 image->cache=DestroyPixelCache(image->cache);
1425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429 + D e s t r o y I m a g e P i x e l s %
1433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1435 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1437 % The format of the DestroyImagePixels() method is:
1439 % void DestroyImagePixels(Image *image)
1441 % A description of each parameter follows:
1443 % o image: the image.
1446 MagickExport void DestroyImagePixels(Image *image)
1451 assert(image != (const Image *) NULL);
1452 assert(image->signature == MagickSignature);
1453 if (image->debug != MagickFalse)
1454 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1455 assert(image->cache != (Cache) NULL);
1456 cache_info=(CacheInfo *) image->cache;
1457 assert(cache_info->signature == MagickSignature);
1458 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1460 cache_info->methods.destroy_pixel_handler(image);
1464 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1468 + D e s t r o y P i x e l C a c h e %
1472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1474 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1476 % The format of the DestroyPixelCache() method is:
1478 % Cache DestroyPixelCache(Cache cache)
1480 % A description of each parameter follows:
1482 % o cache: the pixel cache.
1486 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1488 switch (cache_info->type)
1492 if (cache_info->mapped == MagickFalse)
1493 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1494 cache_info->pixels);
1496 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1497 (size_t) cache_info->length);
1498 RelinquishMagickResource(MemoryResource,cache_info->length);
1503 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1504 cache_info->length);
1505 RelinquishMagickResource(MapResource,cache_info->length);
1509 if (cache_info->file != -1)
1510 (void) ClosePixelCacheOnDisk(cache_info);
1511 RelinquishMagickResource(DiskResource,cache_info->length);
1517 cache_info->type=UndefinedCache;
1518 cache_info->mapped=MagickFalse;
1519 cache_info->indexes=(IndexPacket *) NULL;
1522 MagickExport Cache DestroyPixelCache(Cache cache)
1527 assert(cache != (Cache) NULL);
1528 cache_info=(CacheInfo *) cache;
1529 assert(cache_info->signature == MagickSignature);
1530 if (cache_info->debug != MagickFalse)
1531 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1532 cache_info->filename);
1533 (void) LockSemaphoreInfo(cache_info->semaphore);
1534 cache_info->reference_count--;
1535 if (cache_info->reference_count != 0)
1537 (void) UnlockSemaphoreInfo(cache_info->semaphore);
1538 return((Cache) NULL);
1540 (void) UnlockSemaphoreInfo(cache_info->semaphore);
1541 if (cache_resources != (SplayTreeInfo *) NULL)
1542 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1543 if (cache_info->debug != MagickFalse)
1546 message[MaxTextExtent];
1548 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1549 cache_info->filename);
1550 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1552 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1553 (cache_info->type != DiskCache)))
1554 RelinquishPixelCachePixels(cache_info);
1557 RelinquishPixelCachePixels(cache_info);
1558 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1560 *cache_info->cache_filename='\0';
1561 if (cache_info->nexus_info != (NexusInfo **) NULL)
1562 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1563 cache_info->number_threads);
1564 if (cache_info->random_info != (RandomInfo *) NULL)
1565 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1566 cache_info->signature=(~MagickSignature);
1567 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1568 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1569 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1570 DestroySemaphoreInfo(&cache_info->semaphore);
1571 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1581 + D e s t r o y P i x e l C a c h e N e x u s %
1585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1589 % The format of the DestroyPixelCacheNexus() method is:
1591 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1592 % const unsigned long number_threads)
1594 % A description of each parameter follows:
1596 % o nexus_info: the nexus to destroy.
1598 % o number_threads: the number of nexus threads.
1602 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1604 if (nexus_info->mapped == MagickFalse)
1605 (void) RelinquishMagickMemory(nexus_info->cache);
1607 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1608 nexus_info->cache=(PixelPacket *) NULL;
1609 nexus_info->pixels=(PixelPacket *) NULL;
1610 nexus_info->indexes=(IndexPacket *) NULL;
1611 nexus_info->length=0;
1612 nexus_info->mapped=MagickFalse;
1615 MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1616 const unsigned long number_threads)
1621 assert(nexus_info != (NexusInfo **) NULL);
1622 for (i=0; i < (long) number_threads; i++)
1624 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1625 RelinquishCacheNexusPixels(nexus_info[i]);
1626 nexus_info[i]->signature=(~MagickSignature);
1627 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1629 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1638 + G e t A u t h e n t i c I n d e x e s F r o m C a c h e %
1642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1644 % GetAuthenticIndexesFromCache() returns the indexes associated with the last
1645 % call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1647 % The format of the GetAuthenticIndexesFromCache() method is:
1649 % IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1651 % A description of each parameter follows:
1653 % o image: the image.
1656 static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1667 if (image->debug != MagickFalse)
1668 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1669 cache_info=(CacheInfo *) image->cache;
1670 id=GetOpenMPThreadId();
1671 assert(id < (long) cache_info->number_threads);
1672 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1681 % G e t A u t h e n t i c I n d e x Q u e u e %
1685 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1687 % GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1688 % indexes associated with the last call to QueueAuthenticPixels() or
1689 % GetVirtualPixels(). NULL is returned if the black channel or colormap
1690 % indexes are not available.
1692 % The format of the GetAuthenticIndexQueue() method is:
1694 % IndexPacket *GetAuthenticIndexQueue(const Image *image)
1696 % A description of each parameter follows:
1698 % o image: the image.
1701 MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1706 assert(image != (const Image *) NULL);
1707 assert(image->signature == MagickSignature);
1708 if (image->debug != MagickFalse)
1709 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1710 assert(image->cache != (Cache) NULL);
1711 cache_info=(CacheInfo *) image->cache;
1712 assert(cache_info->signature == MagickSignature);
1713 if (cache_info->methods.get_authentic_indexes_from_handler ==
1714 (GetAuthenticIndexesFromHandler) NULL)
1715 return((IndexPacket *) NULL);
1716 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1724 + 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 %
1728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1730 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1731 % disk pixel cache as defined by the geometry parameters. A pointer to the
1732 % pixels is returned if the pixels are transferred, otherwise a NULL is
1735 % The format of the GetAuthenticPixelCacheNexus() method is:
1737 % PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1738 % const long y,const unsigned long columns,const unsigned long rows,
1739 % NexusInfo *nexus_info,ExceptionInfo *exception)
1741 % A description of each parameter follows:
1743 % o image: the image.
1745 % o x,y,columns,rows: These values define the perimeter of a region of
1748 % o nexus_info: the cache nexus to return.
1750 % o exception: return any errors or warnings in this structure.
1754 static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1755 NexusInfo *nexus_info)
1760 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1761 nexus_info->region.x;
1762 if (nexus_info->pixels != (cache_info->pixels+offset))
1763 return(MagickFalse);
1767 MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const long x,
1768 const long y,const unsigned long columns,const unsigned long rows,
1769 NexusInfo *nexus_info,ExceptionInfo *exception)
1778 Transfer pixels from the cache.
1780 assert(image != (Image *) NULL);
1781 assert(image->signature == MagickSignature);
1782 if (image->debug != MagickFalse)
1783 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1784 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1785 if (pixels == (PixelPacket *) NULL)
1786 return((PixelPacket *) NULL);
1787 cache_info=(CacheInfo *) image->cache;
1788 assert(cache_info->signature == MagickSignature);
1789 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1791 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1792 return((PixelPacket *) NULL);
1793 if (cache_info->active_index_channel != MagickFalse)
1794 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1795 return((PixelPacket *) NULL);
1800 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1804 + 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 %
1808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1810 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1811 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1813 % The format of the GetAuthenticPixelsFromCache() method is:
1815 % PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1817 % A description of each parameter follows:
1819 % o image: the image.
1822 static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1833 if (image->debug != MagickFalse)
1834 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1835 cache_info=(CacheInfo *) image->cache;
1836 id=GetOpenMPThreadId();
1837 assert(id < (long) cache_info->number_threads);
1838 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1847 % G e t A u t h e n t i c P i x e l Q u e u e %
1851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1853 % GetAuthenticPixelQueue() returns the authentic pixels associated with the
1854 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
1856 % The format of the GetAuthenticPixelQueue() method is:
1858 % PixelPacket *GetAuthenticPixelQueue(const Image image)
1860 % A description of each parameter follows:
1862 % o image: the image.
1865 MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1870 assert(image != (const Image *) NULL);
1871 assert(image->signature == MagickSignature);
1872 if (image->debug != MagickFalse)
1873 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1874 assert(image->cache != (Cache) NULL);
1875 cache_info=(CacheInfo *) image->cache;
1876 assert(cache_info->signature == MagickSignature);
1877 if (cache_info->methods.get_authentic_pixels_from_handler ==
1878 (GetAuthenticPixelsFromHandler) NULL)
1879 return((PixelPacket *) NULL);
1880 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1888 % G e t A u t h e n t i c P i x e l s %
1892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1894 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1895 % region is successfully accessed, a pointer to a PixelPacket array
1896 % representing the region is returned, otherwise NULL is returned.
1898 % The returned pointer may point to a temporary working copy of the pixels
1899 % or it may point to the original pixels in memory. Performance is maximized
1900 % if the selected region is part of one row, or one or more full rows, since
1901 % then there is opportunity to access the pixels in-place (without a copy)
1902 % if the image is in RAM, or in a memory-mapped file. The returned pointer
1903 % should *never* be deallocated by the user.
1905 % Pixels accessed via the returned pointer represent a simple array of type
1906 % PixelPacket. If the image type is CMYK or if the storage class is
1907 % PseduoClass, call GetAuthenticIndexQueue() after invoking
1908 % GetAuthenticPixels() to obtain the black color component or colormap indexes
1909 % (of type IndexPacket) corresponding to the region. Once the PixelPacket
1910 % (and/or IndexPacket) array has been updated, the changes must be saved back
1911 % to the underlying image using SyncAuthenticPixels() or they may be lost.
1913 % The format of the GetAuthenticPixels() method is:
1915 % PixelPacket *GetAuthenticPixels(Image *image,const long x,const long y,
1916 % const unsigned long columns,const unsigned long rows,
1917 % ExceptionInfo *exception)
1919 % A description of each parameter follows:
1921 % o image: the image.
1923 % o x,y,columns,rows: These values define the perimeter of a region of
1926 % o exception: return any errors or warnings in this structure.
1929 MagickExport PixelPacket *GetAuthenticPixels(Image *image,const long x,
1930 const long y,const unsigned long columns,const unsigned long rows,
1931 ExceptionInfo *exception)
1939 assert(image != (Image *) NULL);
1940 assert(image->signature == MagickSignature);
1941 if (image->debug != MagickFalse)
1942 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1943 assert(image->cache != (Cache) NULL);
1944 cache_info=(CacheInfo *) image->cache;
1945 assert(cache_info->signature == MagickSignature);
1946 if (cache_info->methods.get_authentic_pixels_handler ==
1947 (GetAuthenticPixelsHandler) NULL)
1948 return((PixelPacket *) NULL);
1949 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1959 + G e t A u t h e n t i c P i x e l s C a c h e %
1963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1965 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1966 % as defined by the geometry parameters. A pointer to the pixels is returned
1967 % if the pixels are transferred, otherwise a NULL is returned.
1969 % The format of the GetAuthenticPixelsCache() method is:
1971 % PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
1972 % const long y,const unsigned long columns,const unsigned long rows,
1973 % ExceptionInfo *exception)
1975 % A description of each parameter follows:
1977 % o image: the image.
1979 % o x,y,columns,rows: These values define the perimeter of a region of
1982 % o exception: return any errors or warnings in this structure.
1985 static PixelPacket *GetAuthenticPixelsCache(Image *image,const long x,
1986 const long y,const unsigned long columns,const unsigned long rows,
1987 ExceptionInfo *exception)
1998 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
1999 if (cache_info == (Cache) NULL)
2000 return((PixelPacket *) NULL);
2001 id=GetOpenMPThreadId();
2002 assert(id < (long) cache_info->number_threads);
2003 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2004 cache_info->nexus_info[id],exception);
2009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013 + G e t I m a g e E x t e n t %
2017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2019 % GetImageExtent() returns the extent of the pixels associated with the
2020 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
2022 % The format of the GetImageExtent() method is:
2024 % MagickSizeType GetImageExtent(const Image *image)
2026 % A description of each parameter follows:
2028 % o image: the image.
2031 MagickExport MagickSizeType GetImageExtent(const Image *image)
2042 assert(image != (Image *) NULL);
2043 assert(image->signature == MagickSignature);
2044 if (image->debug != MagickFalse)
2045 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2046 assert(image->cache != (Cache) NULL);
2047 cache_info=(CacheInfo *) image->cache;
2048 assert(cache_info->signature == MagickSignature);
2049 id=GetOpenMPThreadId();
2050 assert(id < (long) cache_info->number_threads);
2051 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2060 + G e t I m a g e P i x e l C a c h e %
2064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2066 % GetImagePixelCache() ensures that there is only a single reference to the
2067 % pixel cache to be modified, updating the provided cache pointer to point to
2068 % a clone of the original pixel cache if necessary.
2070 % The format of the GetImagePixelCache method is:
2072 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2073 % ExceptionInfo *exception)
2075 % A description of each parameter follows:
2077 % o image: the image.
2079 % o clone: any value other than MagickFalse clones the cache pixels.
2081 % o exception: return any errors or warnings in this structure.
2085 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2091 Does the image match the pixel cache morphology?
2093 cache_info=(CacheInfo *) image->cache;
2094 if ((image->storage_class != cache_info->storage_class) ||
2095 (image->colorspace != cache_info->colorspace) ||
2096 (image->columns != cache_info->columns) ||
2097 (image->rows != cache_info->rows) ||
2098 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2099 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2100 return(MagickFalse);
2104 MagickExport Cache GetImagePixelCache(Image *image,
2105 const MagickBooleanType clone,ExceptionInfo *exception)
2117 if (image->debug != MagickFalse)
2118 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2120 (void) LockSemaphoreInfo(image->semaphore);
2121 time_limit=GetMagickResourceLimit(TimeResource);
2122 if (cache_timer == 0)
2123 cache_timer=time((time_t *) NULL);
2124 if ((time_limit != MagickResourceInfinity) &&
2125 ((MagickSizeType) (time((time_t *) NULL)-cache_timer) >= time_limit))
2126 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2127 assert(image->cache != (Cache) NULL);
2128 cache_info=(CacheInfo *) image->cache;
2129 destroy=MagickFalse;
2130 (void) LockSemaphoreInfo(cache_info->semaphore);
2131 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2142 clone_image=(*image);
2143 clone_image.cache=ClonePixelCache(cache_info);
2144 clone_info=(CacheInfo *) clone_image.cache;
2145 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
2146 if (status != MagickFalse)
2148 status=OpenPixelCache(&clone_image,IOMode,exception);
2149 if (status != MagickFalse)
2151 if (clone != MagickFalse)
2152 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2153 if (status != MagickFalse)
2156 image->cache=clone_image.cache;
2161 (void) UnlockSemaphoreInfo(cache_info->semaphore);
2162 if (destroy != MagickFalse)
2163 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2164 if (status != MagickFalse)
2167 Ensure the image matches the pixel cache morphology.
2169 image->taint=MagickTrue;
2170 image->type=UndefinedType;
2171 if (image->colorspace == GRAYColorspace)
2172 image->colorspace=RGBColorspace;
2173 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2174 status=OpenPixelCache(image,IOMode,exception);
2176 (void) UnlockSemaphoreInfo(image->semaphore);
2177 if (status == MagickFalse)
2178 return((Cache) NULL);
2179 return(image->cache);
2183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2187 % G e t O n e A u t h e n t i c P i x e l %
2191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2193 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2194 % location. The image background color is returned if an error occurs.
2196 % The format of the GetOneAuthenticPixel() method is:
2198 % MagickBooleanType GetOneAuthenticPixel(const Image image,const long x,
2199 % const long y,PixelPacket *pixel,ExceptionInfo *exception)
2201 % A description of each parameter follows:
2203 % o image: the image.
2205 % o x,y: These values define the location of the pixel to return.
2207 % o pixel: return a pixel at the specified (x,y) location.
2209 % o exception: return any errors or warnings in this structure.
2212 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,const long x,
2213 const long y,PixelPacket *pixel,ExceptionInfo *exception)
2218 GetOneAuthenticPixelFromHandler
2219 get_one_authentic_pixel_from_handler;
2224 assert(image != (Image *) NULL);
2225 assert(image->signature == MagickSignature);
2226 if (image->debug != MagickFalse)
2227 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2228 assert(image->cache != (Cache) NULL);
2229 cache_info=(CacheInfo *) image->cache;
2230 assert(cache_info->signature == MagickSignature);
2231 *pixel=image->background_color;
2232 get_one_authentic_pixel_from_handler=
2233 cache_info->methods.get_one_authentic_pixel_from_handler;
2234 if (get_one_authentic_pixel_from_handler ==
2235 (GetOneAuthenticPixelFromHandler) NULL)
2236 return(MagickFalse);
2237 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2247 + 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 %
2251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2253 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2254 % location. The image background color is returned if an error occurs.
2256 % The format of the GetOneAuthenticPixelFromCache() method is:
2258 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2259 % const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2261 % A description of each parameter follows:
2263 % o image: the image.
2265 % o x,y: These values define the location of the pixel to return.
2267 % o pixel: return a pixel at the specified (x,y) location.
2269 % o exception: return any errors or warnings in this structure.
2272 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2273 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2278 if (image->debug != MagickFalse)
2279 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2280 *pixel=image->background_color;
2281 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2282 if (pixels == (PixelPacket *) NULL)
2283 return(MagickFalse);
2289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2293 % G e t O n e V i r t u a l M a g i c k P i x e l %
2297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2299 % GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2300 % location. The image background color is returned if an error occurs. If
2301 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2303 % The format of the GetOneVirtualMagickPixel() method is:
2305 % MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2306 % const long x,const long y,MagickPixelPacket *pixel,
2307 % ExceptionInfo exception)
2309 % A description of each parameter follows:
2311 % o image: the image.
2313 % o x,y: these values define the location of the pixel to return.
2315 % o pixel: return a pixel at the specified (x,y) location.
2317 % o exception: return any errors or warnings in this structure.
2320 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2321 const long x,const long y,MagickPixelPacket *pixel,ExceptionInfo *exception)
2326 register const IndexPacket
2329 register const PixelPacket
2332 assert(image != (const Image *) NULL);
2333 assert(image->signature == MagickSignature);
2334 assert(image->cache != (Cache) NULL);
2335 cache_info=(CacheInfo *) image->cache;
2336 assert(cache_info->signature == MagickSignature);
2337 GetMagickPixelPacket(image,pixel);
2338 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2340 if (p == (const PixelPacket *) NULL)
2341 return(MagickFalse);
2342 indexes=GetVirtualIndexQueue(image);
2343 SetMagickPixelPacket(image,p,indexes,pixel);
2348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2352 % G e t O n e V i r t u a l M e t h o d P i x e l %
2356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2358 % GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2359 % location as defined by specified pixel method. The image background color
2360 % is returned if an error occurs. If you plan to modify the pixel, use
2361 % GetOneAuthenticPixel() instead.
2363 % The format of the GetOneVirtualMethodPixel() method is:
2365 % MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2366 % const VirtualPixelMethod virtual_pixel_method,const long x,
2367 % const long y,Pixelpacket *pixel,ExceptionInfo exception)
2369 % A description of each parameter follows:
2371 % o image: the image.
2373 % o virtual_pixel_method: the virtual pixel method.
2375 % o x,y: These values define the location of the pixel to return.
2377 % o pixel: return a pixel at the specified (x,y) location.
2379 % o exception: return any errors or warnings in this structure.
2382 MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2383 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2384 PixelPacket *pixel,ExceptionInfo *exception)
2386 GetOneVirtualPixelFromHandler
2387 get_one_virtual_pixel_from_handler;
2395 assert(image != (const Image *) NULL);
2396 assert(image->signature == MagickSignature);
2397 assert(image->cache != (Cache) NULL);
2398 cache_info=(CacheInfo *) image->cache;
2399 assert(cache_info->signature == MagickSignature);
2400 *pixel=image->background_color;
2401 get_one_virtual_pixel_from_handler=
2402 cache_info->methods.get_one_virtual_pixel_from_handler;
2403 if (get_one_virtual_pixel_from_handler ==
2404 (GetOneVirtualPixelFromHandler) NULL)
2405 return(MagickFalse);
2406 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2416 % G e t O n e V i r t u a l P i x e l %
2420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2422 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2423 % (x,y) location. The image background color is returned if an error occurs.
2424 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2426 % The format of the GetOneVirtualPixel() method is:
2428 % MagickBooleanType GetOneVirtualPixel(const Image image,const long x,
2429 % const long y,PixelPacket *pixel,ExceptionInfo exception)
2431 % A description of each parameter follows:
2433 % o image: the image.
2435 % o x,y: These values define the location of the pixel to return.
2437 % o pixel: return a pixel at the specified (x,y) location.
2439 % o exception: return any errors or warnings in this structure.
2442 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2443 const long x,const long y,PixelPacket *pixel,ExceptionInfo *exception)
2445 GetOneVirtualPixelFromHandler
2446 get_one_virtual_pixel_from_handler;
2454 assert(image != (const Image *) NULL);
2455 assert(image->signature == MagickSignature);
2456 assert(image->cache != (Cache) NULL);
2457 cache_info=(CacheInfo *) image->cache;
2458 assert(cache_info->signature == MagickSignature);
2459 *pixel=image->background_color;
2460 get_one_virtual_pixel_from_handler=
2461 cache_info->methods.get_one_virtual_pixel_from_handler;
2462 if (get_one_virtual_pixel_from_handler ==
2463 (GetOneVirtualPixelFromHandler) NULL)
2464 return(MagickFalse);
2465 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2466 image),x,y,pixel,exception);
2471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2475 + 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 %
2479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2481 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2482 % specified (x,y) location. The image background color is returned if an
2485 % The format of the GetOneVirtualPixelFromCache() method is:
2487 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2488 % const VirtualPixelPacket method,const long x,const long y,
2489 % PixelPacket *pixel,ExceptionInfo *exception)
2491 % A description of each parameter follows:
2493 % o image: the image.
2495 % o virtual_pixel_method: the virtual pixel method.
2497 % o x,y: These values define the location of the pixel to return.
2499 % o pixel: return a pixel at the specified (x,y) location.
2501 % o exception: return any errors or warnings in this structure.
2504 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2505 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
2506 PixelPacket *pixel,ExceptionInfo *exception)
2511 *pixel=image->background_color;
2512 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2513 if (pixels == (const PixelPacket *) NULL)
2514 return(MagickFalse);
2520 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2524 + G e t P i x e l C a c h e C o l o r s p a c e %
2528 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2530 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2532 % The format of the GetPixelCacheColorspace() method is:
2534 % Colorspace GetPixelCacheColorspace(Cache cache)
2536 % A description of each parameter follows:
2538 % o cache: the pixel cache.
2541 MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2546 assert(cache != (Cache) NULL);
2547 cache_info=(CacheInfo *) cache;
2548 assert(cache_info->signature == MagickSignature);
2549 if (cache_info->debug != MagickFalse)
2550 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2551 cache_info->filename);
2552 return(cache_info->colorspace);
2556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2560 + G e t P i x e l C a c h e M e t h o d s %
2564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2566 % GetPixelCacheMethods() initializes the CacheMethods structure.
2568 % The format of the GetPixelCacheMethods() method is:
2570 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2572 % A description of each parameter follows:
2574 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2577 MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2579 assert(cache_methods != (CacheMethods *) NULL);
2580 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2581 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2582 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2583 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2584 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2585 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2586 cache_methods->get_authentic_indexes_from_handler=
2587 GetAuthenticIndexesFromCache;
2588 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2589 cache_methods->get_one_authentic_pixel_from_handler=
2590 GetOneAuthenticPixelFromCache;
2591 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2592 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2593 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2601 + G e t P i x e l C a c h e N e x u s E x t e n t %
2605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2607 % GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2608 % the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2610 % The format of the GetPixelCacheNexusExtent() method is:
2612 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2613 % NexusInfo *nexus_info)
2615 % A description of each parameter follows:
2617 % o nexus_info: the nexus info.
2620 MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2621 NexusInfo *nexus_info)
2629 if (cache == (Cache) NULL)
2631 cache_info=(CacheInfo *) cache;
2632 assert(cache_info->signature == MagickSignature);
2633 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2635 return((MagickSizeType) cache_info->columns*cache_info->rows);
2640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2644 + G e t P i x e l C a c h e N e x u s I n d e x e s %
2648 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2650 % GetPixelCacheNexusIndexes() returns the indexes associated with the
2651 % specified cache nexus.
2653 % The format of the GetPixelCacheNexusIndexes() method is:
2655 % IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2656 % NexusInfo *nexus_info)
2658 % A description of each parameter follows:
2660 % o cache: the pixel cache.
2662 % o nexus_info: the cache nexus to return the colormap indexes.
2665 MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2666 NexusInfo *nexus_info)
2671 if (cache == (Cache) NULL)
2672 return((IndexPacket *) NULL);
2673 cache_info=(CacheInfo *) cache;
2674 assert(cache_info->signature == MagickSignature);
2675 if (cache_info->storage_class == UndefinedClass)
2676 return((IndexPacket *) NULL);
2677 return(nexus_info->indexes);
2681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2685 + G e t P i x e l C a c h e N e x u s P i x e l s %
2689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2691 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2694 % The format of the GetPixelCacheNexusPixels() method is:
2696 % PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2697 % NexusInfo *nexus_info)
2699 % A description of each parameter follows:
2701 % o cache: the pixel cache.
2703 % o nexus_info: the cache nexus to return the pixels.
2706 MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2707 NexusInfo *nexus_info)
2712 if (cache == (Cache) NULL)
2713 return((PixelPacket *) NULL);
2714 cache_info=(CacheInfo *) cache;
2715 assert(cache_info->signature == MagickSignature);
2716 if (cache_info->debug != MagickFalse)
2717 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2718 cache_info->filename);
2719 if (cache_info->storage_class == UndefinedClass)
2720 return((PixelPacket *) NULL);
2721 return(nexus_info->pixels);
2725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2729 + 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 %
2733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2735 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2737 % The format of the GetPixelCacheStorageClass() method is:
2739 % ClassType GetPixelCacheStorageClass(Cache cache)
2741 % A description of each parameter follows:
2743 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2745 % o cache: the pixel cache.
2748 MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2753 assert(cache != (Cache) NULL);
2754 cache_info=(CacheInfo *) cache;
2755 assert(cache_info->signature == MagickSignature);
2756 if (cache_info->debug != MagickFalse)
2757 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2758 cache_info->filename);
2759 return(cache_info->storage_class);
2763 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2767 + G e t P i x e l C a c h e T i l e S i z e %
2771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2773 % GetPixelCacheTileSize() returns the pixel cache tile size.
2775 % The format of the GetPixelCacheTileSize() method is:
2777 % void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2778 % unsigned long *height)
2780 % A description of each parameter follows:
2782 % o image: the image.
2784 % o width: the optimize cache tile width in pixels.
2786 % o height: the optimize cache tile height in pixels.
2789 MagickExport void GetPixelCacheTileSize(const Image *image,unsigned long *width,
2790 unsigned long *height)
2795 assert(image != (Image *) NULL);
2796 assert(image->signature == MagickSignature);
2797 if (image->debug != MagickFalse)
2798 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2799 assert(image->cache != (Cache) NULL);
2800 cache_info=(CacheInfo *) image->cache;
2801 assert(cache_info->signature == MagickSignature);
2802 *width=2048UL/sizeof(PixelPacket);
2803 if (GetPixelCacheType(image) == DiskCache)
2804 *width=8192UL/sizeof(PixelPacket);
2809 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2813 + G e t P i x e l C a c h e T y p e %
2817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2819 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2821 % The format of the GetPixelCacheType() method is:
2823 % CacheType GetPixelCacheType(const Image *image)
2825 % A description of each parameter follows:
2827 % o image: the image.
2830 MagickExport CacheType GetPixelCacheType(const Image *image)
2835 assert(image != (Image *) NULL);
2836 assert(image->signature == MagickSignature);
2837 if (image->debug != MagickFalse)
2838 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2839 assert(image->cache != (Cache) NULL);
2840 cache_info=(CacheInfo *) image->cache;
2841 assert(cache_info->signature == MagickSignature);
2842 return(cache_info->type);
2846 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2850 + 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 %
2854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2856 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2857 % pixel cache. A virtual pixel is any pixel access that is outside the
2858 % boundaries of the image cache.
2860 % The format of the GetPixelCacheVirtualMethod() method is:
2862 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2864 % A description of each parameter follows:
2866 % o image: the image.
2869 MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2874 assert(image != (Image *) NULL);
2875 assert(image->signature == MagickSignature);
2876 if (image->debug != MagickFalse)
2877 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2878 assert(image->cache != (Cache) NULL);
2879 cache_info=(CacheInfo *) image->cache;
2880 assert(cache_info->signature == MagickSignature);
2881 return(cache_info->virtual_pixel_method);
2885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2889 + G e t V i r t u a l I n d e x e s F r o m C a c h e %
2893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2895 % GetVirtualIndexesFromCache() returns the indexes associated with the last
2896 % call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2898 % The format of the GetVirtualIndexesFromCache() method is:
2900 % IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2902 % A description of each parameter follows:
2904 % o image: the image.
2907 static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2918 if (image->debug != MagickFalse)
2919 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2920 cache_info=(CacheInfo *) image->cache;
2921 id=GetOpenMPThreadId();
2922 assert(id < (long) cache_info->number_threads);
2923 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
2928 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2932 + G e t V i r t u a l I n d e x e s F r o m N e x u s %
2936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2938 % GetVirtualIndexesFromNexus() returns the indexes associated with the
2939 % specified cache nexus.
2941 % The format of the GetVirtualIndexesFromNexus() method is:
2943 % const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2944 % NexusInfo *nexus_info)
2946 % A description of each parameter follows:
2948 % o cache: the pixel cache.
2950 % o nexus_info: the cache nexus to return the colormap indexes.
2953 MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2954 NexusInfo *nexus_info)
2959 if (cache == (Cache) NULL)
2960 return((IndexPacket *) NULL);
2961 cache_info=(CacheInfo *) cache;
2962 assert(cache_info->signature == MagickSignature);
2963 if (cache_info->storage_class == UndefinedClass)
2964 return((IndexPacket *) NULL);
2965 return(nexus_info->indexes);
2969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2973 % G e t V i r t u a l I n d e x Q u e u e %
2977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2979 % GetVirtualIndexQueue() returns the virtual black channel or the
2980 % colormap indexes associated with the last call to QueueAuthenticPixels() or
2981 % GetVirtualPixels(). NULL is returned if the black channel or colormap
2982 % indexes are not available.
2984 % The format of the GetVirtualIndexQueue() method is:
2986 % const IndexPacket *GetVirtualIndexQueue(const Image *image)
2988 % A description of each parameter follows:
2990 % o image: the image.
2993 MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
2998 assert(image != (const Image *) NULL);
2999 assert(image->signature == MagickSignature);
3000 if (image->debug != MagickFalse)
3001 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3002 assert(image->cache != (Cache) NULL);
3003 cache_info=(CacheInfo *) image->cache;
3004 assert(cache_info->signature == MagickSignature);
3005 if (cache_info->methods.get_virtual_indexes_from_handler ==
3006 (GetVirtualIndexesFromHandler) NULL)
3007 return((IndexPacket *) NULL);
3008 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3016 + G e t V i r t u a l P i x e l s F r o m N e x u s %
3020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3022 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3023 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3024 % is returned if the pixels are transferred, otherwise a NULL is returned.
3026 % The format of the GetVirtualPixelsFromNexus() method is:
3028 % PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3029 % const VirtualPixelMethod method,const long x,const long y,
3030 % const unsigned long columns,const unsigned long rows,
3031 % NexusInfo *nexus_info,ExceptionInfo *exception)
3033 % A description of each parameter follows:
3035 % o image: the image.
3037 % o virtual_pixel_method: the virtual pixel method.
3039 % o x,y,columns,rows: These values define the perimeter of a region of
3042 % o nexus_info: the cache nexus to acquire.
3044 % o exception: return any errors or warnings in this structure.
3051 0, 48, 12, 60, 3, 51, 15, 63,
3052 32, 16, 44, 28, 35, 19, 47, 31,
3053 8, 56, 4, 52, 11, 59, 7, 55,
3054 40, 24, 36, 20, 43, 27, 39, 23,
3055 2, 50, 14, 62, 1, 49, 13, 61,
3056 34, 18, 46, 30, 33, 17, 45, 29,
3057 10, 58, 6, 54, 9, 57, 5, 53,
3058 42, 26, 38, 22, 41, 25, 37, 21
3061 static inline long DitherX(const unsigned long columns,const long x)
3066 index=x+DitherMatrix[x & 0x07]-32L;
3069 if (index >= (long) columns)
3070 return((long) columns-1L);
3074 static inline long DitherY(const unsigned long rows,const long y)
3079 index=y+DitherMatrix[y & 0x07]-32L;
3082 if (index >= (long) rows)
3083 return((long) rows-1L);
3087 static inline long EdgeX(const unsigned long columns,const long x)
3091 if (x >= (long) columns)
3092 return((long) columns-1L);
3096 static inline long EdgeY(const unsigned long rows,const long y)
3100 if (y >= (long) rows)
3101 return((long) rows-1L);
3105 static inline long RandomX(const unsigned long columns,RandomInfo *random_info)
3107 return((long) (columns*GetPseudoRandomValue(random_info)));
3110 static inline long RandomY(const unsigned long rows,RandomInfo *random_info)
3112 return((long) (rows*GetPseudoRandomValue(random_info)));
3116 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3117 returns not only the quotient (tile the offset falls in) but also the positive
3118 remainer within that tile such that 0 <= remainder < extent. This method is
3119 essentially a ldiv() using a floored modulo division rather than the normal
3120 default truncated modulo division.
3122 static inline MagickModulo VirtualPixelModulo(const long offset,
3123 const unsigned long extent)
3128 modulo.quotient=offset/(long) extent;
3131 modulo.remainder=offset-modulo.quotient*(long) extent;
3135 MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3136 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3137 const unsigned long columns,const unsigned long rows,NexusInfo *nexus_info,
3138 ExceptionInfo *exception)
3160 register const IndexPacket
3161 *__restrict nexus_indexes;
3163 register const PixelPacket
3166 register IndexPacket
3167 *__restrict indexes;
3173 register PixelPacket
3179 if (image->debug != MagickFalse)
3180 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3181 cache_info=(CacheInfo *) image->cache;
3182 if (cache_info->type == UndefinedCache)
3183 return((const PixelPacket *) NULL);
3186 region.width=columns;
3188 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3189 if (pixels == (PixelPacket *) NULL)
3190 return((const PixelPacket *) NULL);
3191 offset=(MagickOffsetType) region.y*cache_info->columns+region.x;
3192 length=(MagickSizeType) (region.height-1)*cache_info->columns+region.width-1;
3193 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3194 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3195 if ((x >= 0) && ((long) (x+columns) <= (long) cache_info->columns) &&
3196 (y >= 0) && ((long) (y+rows) <= (long) cache_info->rows))
3202 Pixel request is inside cache extents.
3204 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3206 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3207 if (status == MagickFalse)
3208 return((const PixelPacket *) NULL);
3209 if ((cache_info->storage_class == PseudoClass) ||
3210 (cache_info->colorspace == CMYKColorspace))
3212 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3213 if (status == MagickFalse)
3214 return((const PixelPacket *) NULL);
3219 Pixel request is outside cache extents.
3222 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3223 virtual_nexus=AcquirePixelCacheNexus(1);
3224 if (virtual_nexus == (NexusInfo **) NULL)
3226 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3227 "UnableToGetCacheNexus","`%s'",image->filename);
3228 return((const PixelPacket *) NULL);
3230 switch (virtual_pixel_method)
3232 case BlackVirtualPixelMethod:
3234 virtual_pixel.red=0;
3235 virtual_pixel.green=0;
3236 virtual_pixel.blue=0;
3237 virtual_pixel.opacity=OpaqueOpacity;
3240 case GrayVirtualPixelMethod:
3242 virtual_pixel.red=(Quantum) QuantumRange/2;
3243 virtual_pixel.green=(Quantum) QuantumRange/2;
3244 virtual_pixel.blue=(Quantum) QuantumRange/2;
3245 virtual_pixel.opacity=(Quantum) OpaqueOpacity;
3248 case TransparentVirtualPixelMethod:
3250 virtual_pixel.red=(Quantum) 0;
3251 virtual_pixel.green=(Quantum) 0;
3252 virtual_pixel.blue=(Quantum) 0;
3253 virtual_pixel.opacity=(Quantum) TransparentOpacity;
3256 case MaskVirtualPixelMethod:
3257 case WhiteVirtualPixelMethod:
3259 virtual_pixel.red=(Quantum) QuantumRange;
3260 virtual_pixel.green=(Quantum) QuantumRange;
3261 virtual_pixel.blue=(Quantum) QuantumRange;
3262 virtual_pixel.opacity=OpaqueOpacity;
3267 virtual_pixel=image->background_color;
3271 for (v=0; v < (long) rows; v++)
3273 for (u=0; u < (long) columns; u+=length)
3275 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3276 if ((((x+u) < 0) || ((x+u) >= (long) cache_info->columns)) ||
3277 (((y+v) < 0) || ((y+v) >= (long) cache_info->rows)) || (length == 0))
3284 Transfer a single pixel.
3286 length=(MagickSizeType) 1;
3287 switch (virtual_pixel_method)
3289 case BackgroundVirtualPixelMethod:
3290 case ConstantVirtualPixelMethod:
3291 case BlackVirtualPixelMethod:
3292 case GrayVirtualPixelMethod:
3293 case TransparentVirtualPixelMethod:
3294 case MaskVirtualPixelMethod:
3295 case WhiteVirtualPixelMethod:
3300 case EdgeVirtualPixelMethod:
3303 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3304 EdgeX(cache_info->columns,x+u),EdgeY(cache_info->rows,y+v),
3305 1UL,1UL,virtual_nexus[0],exception);
3308 case RandomVirtualPixelMethod:
3310 if (cache_info->random_info == (RandomInfo *) NULL)
3311 cache_info->random_info=AcquireRandomInfo();
3312 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3313 RandomX(cache_info->columns,cache_info->random_info),
3314 RandomY(cache_info->rows,cache_info->random_info),1UL,1UL,
3315 virtual_nexus[0],exception);
3318 case DitherVirtualPixelMethod:
3320 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3321 DitherX(cache_info->columns,x+u),DitherY(cache_info->rows,y+v),
3322 1UL,1UL,virtual_nexus[0],exception);
3325 case TileVirtualPixelMethod:
3327 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3328 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3329 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3330 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3334 case MirrorVirtualPixelMethod:
3336 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3337 if ((x_modulo.quotient & 0x01) == 1L)
3338 x_modulo.remainder=(long) cache_info->columns-
3339 x_modulo.remainder-1L;
3340 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3341 if ((y_modulo.quotient & 0x01) == 1L)
3342 y_modulo.remainder=(long) cache_info->rows-
3343 y_modulo.remainder-1L;
3344 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3345 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3349 case CheckerTileVirtualPixelMethod:
3351 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3352 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3353 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3358 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3359 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3363 case HorizontalTileVirtualPixelMethod:
3365 if (((y+v) < 0) || ((y+v) >= (long) cache_info->rows))
3370 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3371 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3372 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3373 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3377 case VerticalTileVirtualPixelMethod:
3379 if (((x+u) < 0) || ((x+u) >= (long) cache_info->columns))
3384 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3385 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3386 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3387 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3391 case HorizontalTileEdgeVirtualPixelMethod:
3393 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3394 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3395 x_modulo.remainder,EdgeY(cache_info->rows,y+v),1UL,1UL,
3396 virtual_nexus[0],exception);
3399 case VerticalTileEdgeVirtualPixelMethod:
3401 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3402 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3403 EdgeX(cache_info->columns,x+u),y_modulo.remainder,1UL,1UL,
3404 virtual_nexus[0],exception);
3408 if (p == (const PixelPacket *) NULL)
3411 if (indexes != (IndexPacket *) NULL)
3413 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,
3415 if (nexus_indexes != (const IndexPacket *) NULL)
3416 *indexes++=(*nexus_indexes);
3421 Transfer a run of pixels.
3423 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3424 (unsigned long) length,1UL,virtual_nexus[0],exception);
3425 if (p == (const PixelPacket *) NULL)
3427 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3429 if (indexes != (IndexPacket *) NULL)
3431 nexus_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
3432 if (nexus_indexes != (const IndexPacket *) NULL)
3434 (void) CopyMagickMemory(indexes,nexus_indexes,(size_t) length*
3435 sizeof(*nexus_indexes));
3441 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3450 + G e t V i r t u a l P i x e l C a c h e %
3454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3456 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3457 % cache as defined by the geometry parameters. A pointer to the pixels
3458 % is returned if the pixels are transferred, otherwise a NULL is returned.
3460 % The format of the GetVirtualPixelCache() method is:
3462 % const PixelPacket *GetVirtualPixelCache(const Image *image,
3463 % const VirtualPixelMethod virtual_pixel_method,const long x,
3464 % const long y,const unsigned long columns,const unsigned long rows,
3465 % ExceptionInfo *exception)
3467 % A description of each parameter follows:
3469 % o image: the image.
3471 % o virtual_pixel_method: the virtual pixel method.
3473 % o x,y,columns,rows: These values define the perimeter of a region of
3476 % o exception: return any errors or warnings in this structure.
3479 static const PixelPacket *GetVirtualPixelCache(const Image *image,
3480 const VirtualPixelMethod virtual_pixel_method,const long x,const long y,
3481 const unsigned long columns,const unsigned long rows,ExceptionInfo *exception)
3492 if (image->debug != MagickFalse)
3493 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3494 cache_info=(CacheInfo *) image->cache;
3495 id=GetOpenMPThreadId();
3496 assert(id < (long) cache_info->number_threads);
3497 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3498 cache_info->nexus_info[id],exception);
3503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3507 % G e t V i r t u a l P i x e l Q u e u e %
3511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3513 % GetVirtualPixelQueue() returns the virtual pixels associated with the
3514 % last call to QueueAuthenticPixels() or GetVirtualPixels().
3516 % The format of the GetVirtualPixelQueue() method is:
3518 % const PixelPacket *GetVirtualPixelQueue(const Image image)
3520 % A description of each parameter follows:
3522 % o image: the image.
3525 MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3530 assert(image != (const Image *) NULL);
3531 assert(image->signature == MagickSignature);
3532 if (image->debug != MagickFalse)
3533 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3534 assert(image->cache != (Cache) NULL);
3535 cache_info=(CacheInfo *) image->cache;
3536 assert(cache_info->signature == MagickSignature);
3537 if (cache_info->methods.get_virtual_pixels_handler ==
3538 (GetVirtualPixelsHandler) NULL)
3539 return((PixelPacket *) NULL);
3540 return(cache_info->methods.get_virtual_pixels_handler(image));
3544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3548 % G e t V i r t u a l P i x e l s %
3552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3554 % GetVirtualPixels() returns an immutable pixel region. If the
3555 % region is successfully accessed, a pointer to it is returned, otherwise
3556 % NULL is returned. The returned pointer may point to a temporary working
3557 % copy of the pixels or it may point to the original pixels in memory.
3558 % Performance is maximized if the selected region is part of one row, or one
3559 % or more full rows, since there is opportunity to access the pixels in-place
3560 % (without a copy) if the image is in RAM, or in a memory-mapped file. The
3561 % returned pointer should *never* be deallocated by the user.
3563 % Pixels accessed via the returned pointer represent a simple array of type
3564 % PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3565 % call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3566 % the black color component or to obtain the colormap indexes (of type
3567 % IndexPacket) corresponding to the region.
3569 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3571 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3572 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3573 % GetCacheViewAuthenticPixels() instead.
3575 % The format of the GetVirtualPixels() method is:
3577 % const PixelPacket *GetVirtualPixels(const Image *image,const long x,
3578 % const long y,const unsigned long columns,const unsigned long rows,
3579 % ExceptionInfo *exception)
3581 % A description of each parameter follows:
3583 % o image: the image.
3585 % o x,y,columns,rows: These values define the perimeter of a region of
3588 % o exception: return any errors or warnings in this structure.
3591 MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3592 const long x,const long y,const unsigned long columns,
3593 const unsigned long rows,ExceptionInfo *exception)
3601 assert(image != (const Image *) NULL);
3602 assert(image->signature == MagickSignature);
3603 if (image->debug != MagickFalse)
3604 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3605 assert(image->cache != (Cache) NULL);
3606 cache_info=(CacheInfo *) image->cache;
3607 assert(cache_info->signature == MagickSignature);
3608 if (cache_info->methods.get_virtual_pixel_handler ==
3609 (GetVirtualPixelHandler) NULL)
3610 return((const PixelPacket *) NULL);
3611 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3612 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3621 + 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 %
3625 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3627 % GetVirtualPixelsCache() returns the pixels associated with the last call
3628 % to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3630 % The format of the GetVirtualPixelsCache() method is:
3632 % PixelPacket *GetVirtualPixelsCache(const Image *image)
3634 % A description of each parameter follows:
3636 % o image: the image.
3639 static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3650 if (image->debug != MagickFalse)
3651 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3652 cache_info=(CacheInfo *) image->cache;
3653 id=GetOpenMPThreadId();
3654 assert(id < (long) cache_info->number_threads);
3655 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3664 + G e t V i r t u a l P i x e l s N e x u s %
3668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3670 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3673 % The format of the GetVirtualPixelsNexus() method is:
3675 % const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3676 % NexusInfo *nexus_info)
3678 % A description of each parameter follows:
3680 % o cache: the pixel cache.
3682 % o nexus_info: the cache nexus to return the colormap pixels.
3685 MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3686 NexusInfo *nexus_info)
3691 if (cache == (Cache) NULL)
3692 return((PixelPacket *) NULL);
3693 cache_info=(CacheInfo *) cache;
3694 assert(cache_info->signature == MagickSignature);
3695 if (cache_info->storage_class == UndefinedClass)
3696 return((PixelPacket *) NULL);
3697 return((const PixelPacket *) nexus_info->pixels);
3701 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3705 + M a s k P i x e l C a c h e N e x u s %
3709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3711 % MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3712 % The method returns MagickTrue if the pixel region is masked, otherwise
3715 % The format of the MaskPixelCacheNexus() method is:
3717 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3718 % NexusInfo *nexus_info,ExceptionInfo *exception)
3720 % A description of each parameter follows:
3722 % o image: the image.
3724 % o nexus_info: the cache nexus to clip.
3726 % o exception: return any errors or warnings in this structure.
3730 static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3731 const MagickRealType alpha,const MagickPixelPacket *q,
3732 const MagickRealType beta,MagickPixelPacket *composite)
3737 if (alpha == TransparentOpacity)
3742 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3743 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3744 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3745 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3746 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3747 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3748 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3751 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3752 ExceptionInfo *exception)
3768 register const PixelPacket
3771 register IndexPacket
3772 *__restrict nexus_indexes,
3773 *__restrict indexes;
3778 register PixelPacket
3785 if (image->debug != MagickFalse)
3786 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3787 if (image->mask == (Image *) NULL)
3788 return(MagickFalse);
3789 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3790 if (cache_info == (Cache) NULL)
3791 return(MagickFalse);
3792 image_nexus=AcquirePixelCacheNexus(1);
3793 clip_nexus=AcquirePixelCacheNexus(1);
3794 if ((image_nexus == (NexusInfo **) NULL) ||
3795 (clip_nexus == (NexusInfo **) NULL))
3796 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3797 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
3798 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
3800 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3801 q=nexus_info->pixels;
3802 nexus_indexes=nexus_info->indexes;
3803 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3804 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3805 nexus_info->region.height,clip_nexus[0],&image->exception);
3806 GetMagickPixelPacket(image,&alpha);
3807 GetMagickPixelPacket(image,&beta);
3808 number_pixels=(MagickSizeType) nexus_info->region.width*
3809 nexus_info->region.height;
3810 for (i=0; i < (long) number_pixels; i++)
3812 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3814 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3815 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3816 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3817 &alpha,alpha.opacity,&beta);
3818 q->red=RoundToQuantum(beta.red);
3819 q->green=RoundToQuantum(beta.green);
3820 q->blue=RoundToQuantum(beta.blue);
3821 q->opacity=RoundToQuantum(beta.opacity);
3822 if (cache_info->active_index_channel != MagickFalse)
3823 nexus_indexes[i]=indexes[i];
3828 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3829 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3830 if (i < (long) number_pixels)
3831 return(MagickFalse);
3836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3840 + O p e n P i x e l C a c h e %
3844 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3846 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3847 % dimensions, allocating space for the image pixels and optionally the
3848 % colormap indexes, and memory mapping the cache if it is disk based. The
3849 % cache nexus array is initialized as well.
3851 % The format of the OpenPixelCache() method is:
3853 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3854 % ExceptionInfo *exception)
3856 % A description of each parameter follows:
3858 % o image: the image.
3860 % o mode: ReadMode, WriteMode, or IOMode.
3862 % o exception: return any errors or warnings in this structure.
3866 static inline void AcquirePixelCachePixels(CacheInfo *cache_info)
3868 cache_info->mapped=MagickFalse;
3869 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3870 cache_info->length);
3871 if (cache_info->pixels == (PixelPacket *) NULL)
3873 cache_info->mapped=MagickTrue;
3874 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3875 cache_info->length);
3879 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3889 cache_info=(CacheInfo *) image->cache;
3890 if (image->debug != MagickFalse)
3893 format[MaxTextExtent],
3894 message[MaxTextExtent];
3896 (void) FormatMagickSize(length,format);
3897 (void) FormatMagickString(message,MaxTextExtent,
3898 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3899 cache_info->cache_filename,cache_info->file,format);
3900 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3902 if (length != (MagickSizeType) ((MagickOffsetType) length))
3903 return(MagickFalse);
3904 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3906 return(MagickFalse);
3907 if ((MagickSizeType) extent >= length)
3909 offset=(MagickOffsetType) length-1;
3910 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3911 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3914 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3915 ExceptionInfo *exception)
3918 format[MaxTextExtent],
3919 message[MaxTextExtent];
3938 if (image->debug != MagickFalse)
3939 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3940 if ((image->columns == 0) || (image->rows == 0))
3941 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3942 cache_info=(CacheInfo *) image->cache;
3943 source_info=(*cache_info);
3944 source_info.file=(-1);
3945 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%ld]",
3946 image->filename,GetImageIndexInList(image));
3947 cache_info->mode=mode;
3948 cache_info->rows=image->rows;
3949 cache_info->columns=image->columns;
3950 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3951 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
3952 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3953 packet_size=sizeof(PixelPacket);
3954 if (cache_info->active_index_channel != MagickFalse)
3955 packet_size+=sizeof(IndexPacket);
3956 length=number_pixels*packet_size;
3957 columns=(unsigned long) (length/cache_info->rows/packet_size);
3958 if (cache_info->columns != columns)
3959 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3961 cache_info->length=length;
3962 status=AcquireMagickResource(AreaResource,cache_info->length);
3963 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
3964 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
3966 status=AcquireMagickResource(MemoryResource,cache_info->length);
3967 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
3968 (cache_info->type == MemoryCache))
3970 AcquirePixelCachePixels(cache_info);
3971 if (cache_info->pixels == (PixelPacket *) NULL)
3972 cache_info->pixels=source_info.pixels;
3976 Create memory pixel cache.
3978 if (image->debug != MagickFalse)
3980 (void) FormatMagickSize(cache_info->length,format);
3981 (void) FormatMagickString(message,MaxTextExtent,
3982 "open %s (%s memory, %lux%lu %s)",cache_info->filename,
3983 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
3984 cache_info->columns,cache_info->rows,format);
3985 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
3988 cache_info->storage_class=image->storage_class;
3989 cache_info->colorspace=image->colorspace;
3990 cache_info->type=MemoryCache;
3991 cache_info->indexes=(IndexPacket *) NULL;
3992 if (cache_info->active_index_channel != MagickFalse)
3993 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
3995 if (source_info.storage_class != UndefinedClass)
3997 status|=ClonePixelCachePixels(cache_info,&source_info,
3999 RelinquishPixelCachePixels(&source_info);
4004 RelinquishMagickResource(MemoryResource,cache_info->length);
4007 Create pixel cache on disk.
4009 status=AcquireMagickResource(DiskResource,cache_info->length);
4010 if (status == MagickFalse)
4012 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4013 "CacheResourcesExhausted","`%s'",image->filename);
4014 return(MagickFalse);
4016 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4018 RelinquishMagickResource(DiskResource,cache_info->length);
4019 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4021 return(MagickFalse);
4023 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4024 cache_info->length);
4025 if (status == MagickFalse)
4027 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4029 return(MagickFalse);
4031 cache_info->storage_class=image->storage_class;
4032 cache_info->colorspace=image->colorspace;
4033 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4034 status=AcquireMagickResource(AreaResource,cache_info->length);
4035 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4036 cache_info->type=DiskCache;
4039 status=AcquireMagickResource(MapResource,cache_info->length);
4040 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4041 (cache_info->type != MemoryCache))
4042 cache_info->type=DiskCache;
4045 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4046 cache_info->offset,(size_t) cache_info->length);
4047 if (cache_info->pixels == (PixelPacket *) NULL)
4049 cache_info->pixels=source_info.pixels;
4050 cache_info->type=DiskCache;
4055 Create file-backed memory-mapped pixel cache.
4057 (void) ClosePixelCacheOnDisk(cache_info);
4058 cache_info->type=MapCache;
4059 cache_info->mapped=MagickTrue;
4060 cache_info->indexes=(IndexPacket *) NULL;
4061 if (cache_info->active_index_channel != MagickFalse)
4062 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4064 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4066 status=ClonePixelCachePixels(cache_info,&source_info,
4068 RelinquishPixelCachePixels(&source_info);
4070 if (image->debug != MagickFalse)
4072 (void) FormatMagickSize(cache_info->length,format);
4073 (void) FormatMagickString(message,MaxTextExtent,
4074 "open %s (%s[%d], memory-mapped, %lux%lu %s)",
4075 cache_info->filename,cache_info->cache_filename,
4076 cache_info->file,cache_info->columns,cache_info->rows,
4078 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4084 RelinquishMagickResource(MapResource,cache_info->length);
4086 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4088 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4089 RelinquishPixelCachePixels(&source_info);
4091 if (image->debug != MagickFalse)
4093 (void) FormatMagickSize(cache_info->length,format);
4094 (void) FormatMagickString(message,MaxTextExtent,
4095 "open %s (%s[%d], disk, %lux%lu %s)",cache_info->filename,
4096 cache_info->cache_filename,cache_info->file,cache_info->columns,
4097 cache_info->rows,format);
4098 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4108 + P e r s i s t P i x e l C a c h e %
4112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4114 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4115 % persistent pixel cache is one that resides on disk and is not destroyed
4116 % when the program exits.
4118 % The format of the PersistPixelCache() method is:
4120 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4121 % const MagickBooleanType attach,MagickOffsetType *offset,
4122 % ExceptionInfo *exception)
4124 % A description of each parameter follows:
4126 % o image: the image.
4128 % o filename: the persistent pixel cache filename.
4130 % o attach: A value other than zero initializes the persistent pixel
4133 % o initialize: A value other than zero initializes the persistent pixel
4136 % o offset: the offset in the persistent cache to store pixels.
4138 % o exception: return any errors or warnings in this structure.
4141 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4142 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4143 ExceptionInfo *exception)
4158 assert(image != (Image *) NULL);
4159 assert(image->signature == MagickSignature);
4160 if (image->debug != MagickFalse)
4161 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4162 assert(image->cache != (void *) NULL);
4163 assert(filename != (const char *) NULL);
4164 assert(offset != (MagickOffsetType *) NULL);
4165 page_size=GetMagickPageSize();
4166 cache_info=(CacheInfo *) image->cache;
4167 assert(cache_info->signature == MagickSignature);
4168 if (attach != MagickFalse)
4171 Attach existing persistent pixel cache.
4173 if (image->debug != MagickFalse)
4174 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4175 "attach persistent cache");
4176 (void) CopyMagickString(cache_info->cache_filename,filename,
4178 cache_info->type=DiskCache;
4179 cache_info->offset=(*offset);
4180 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4181 return(MagickFalse);
4182 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4185 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4186 (cache_info->reference_count == 1))
4188 (void) LockSemaphoreInfo(cache_info->semaphore);
4189 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4190 (cache_info->reference_count == 1))
4196 Usurp existing persistent pixel cache.
4198 status=rename(cache_info->cache_filename,filename);
4201 (void) CopyMagickString(cache_info->cache_filename,filename,
4203 *offset+=cache_info->length+page_size-(cache_info->length %
4205 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4206 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4207 if (image->debug != MagickFalse)
4208 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4209 "Usurp resident persistent cache");
4213 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4216 Clone persistent pixel cache.
4218 clone_image=(*image);
4219 clone_info=(CacheInfo *) clone_image.cache;
4220 image->cache=ClonePixelCache(cache_info);
4221 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4222 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4223 cache_info->type=DiskCache;
4224 cache_info->offset=(*offset);
4225 cache_info=(CacheInfo *) image->cache;
4226 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4227 if (status != MagickFalse)
4229 status=OpenPixelCache(image,IOMode,exception);
4230 if (status != MagickFalse)
4231 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4233 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4234 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4243 + Q u e u e A u t h e n t i c N e x u s %
4247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4249 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4250 % by the region rectangle and returns a pointer to the region. This region is
4251 % subsequently transferred from the pixel cache with
4252 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4253 % pixels are transferred, otherwise a NULL is returned.
4255 % The format of the QueueAuthenticNexus() method is:
4257 % PixelPacket *QueueAuthenticNexus(Image *image,const long x,const long y,
4258 % const unsigned long columns,const unsigned long rows,
4259 % NexusInfo *nexus_info,ExceptionInfo *exception)
4261 % A description of each parameter follows:
4263 % o image: the image.
4265 % o x,y,columns,rows: These values define the perimeter of a region of
4268 % o nexus_info: the cache nexus to set.
4270 % o exception: return any errors or warnings in this structure.
4273 MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const long x,
4274 const long y,const unsigned long columns,const unsigned long rows,
4275 NexusInfo *nexus_info,ExceptionInfo *exception)
4290 Validate pixel cache geometry.
4292 cache_info=(CacheInfo *) image->cache;
4293 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4295 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4296 "NoPixelsDefinedInCache","`%s'",image->filename);
4297 return((PixelPacket *) NULL);
4299 if ((x < 0) || (y < 0) || (x >= (long) cache_info->columns) ||
4300 (y >= (long) cache_info->rows))
4302 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4303 "PixelsAreNotAuthentic","`%s'",image->filename);
4304 return((PixelPacket *) NULL);
4306 offset=(MagickOffsetType) y*cache_info->columns+x;
4308 return((PixelPacket *) NULL);
4309 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4310 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4311 if ((MagickSizeType) offset >= number_pixels)
4312 return((PixelPacket *) NULL);
4318 region.width=columns;
4320 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4328 + 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 %
4332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4334 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4335 % defined by the region rectangle and returns a pointer to the region. This
4336 % region is subsequently transferred from the pixel cache with
4337 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4338 % pixels are transferred, otherwise a NULL is returned.
4340 % The format of the QueueAuthenticPixelsCache() method is:
4342 % PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4343 % const long y,const unsigned long columns,const unsigned long rows,
4344 % ExceptionInfo *exception)
4346 % A description of each parameter follows:
4348 % o image: the image.
4350 % o x,y,columns,rows: These values define the perimeter of a region of
4353 % o exception: return any errors or warnings in this structure.
4356 static PixelPacket *QueueAuthenticPixelsCache(Image *image,const long x,
4357 const long y,const unsigned long columns,const unsigned long rows,
4358 ExceptionInfo *exception)
4369 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4370 if (cache_info == (Cache) NULL)
4371 return((PixelPacket *) NULL);
4372 id=GetOpenMPThreadId();
4373 assert(id < (long) cache_info->number_threads);
4374 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4384 % Q u e u e A u t h e n t i c P i x e l s %
4388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4390 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4391 % successfully intialized a pointer to a PixelPacket array representing the
4392 % region is returned, otherwise NULL is returned. The returned pointer may
4393 % point to a temporary working buffer for the pixels or it may point to the
4394 % final location of the pixels in memory.
4396 % Write-only access means that any existing pixel values corresponding to
4397 % the region are ignored. This is useful if the initial image is being
4398 % created from scratch, or if the existing pixel values are to be
4399 % completely replaced without need to refer to their pre-existing values.
4400 % The application is free to read and write the pixel buffer returned by
4401 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4402 % initialize the pixel array values. Initializing pixel array values is the
4403 % application's responsibility.
4405 % Performance is maximized if the selected region is part of one row, or
4406 % one or more full rows, since then there is opportunity to access the
4407 % pixels in-place (without a copy) if the image is in RAM, or in a
4408 % memory-mapped file. The returned pointer should *never* be deallocated
4411 % Pixels accessed via the returned pointer represent a simple array of type
4412 % PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4413 % call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4414 % the black color component or the colormap indexes (of type IndexPacket)
4415 % corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4416 % array has been updated, the changes must be saved back to the underlying
4417 % image using SyncAuthenticPixels() or they may be lost.
4419 % The format of the QueueAuthenticPixels() method is:
4421 % PixelPacket *QueueAuthenticPixels(Image *image,const long x,const long y,
4422 % const unsigned long columns,const unsigned long rows,
4423 % ExceptionInfo *exception)
4425 % A description of each parameter follows:
4427 % o image: the image.
4429 % o x,y,columns,rows: These values define the perimeter of a region of
4432 % o exception: return any errors or warnings in this structure.
4435 MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const long x,
4436 const long y,const unsigned long columns,const unsigned long rows,
4437 ExceptionInfo *exception)
4445 assert(image != (Image *) NULL);
4446 assert(image->signature == MagickSignature);
4447 if (image->debug != MagickFalse)
4448 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4449 assert(image->cache != (Cache) NULL);
4450 cache_info=(CacheInfo *) image->cache;
4451 assert(cache_info->signature == MagickSignature);
4452 if (cache_info->methods.queue_authentic_pixels_handler ==
4453 (QueueAuthenticPixelsHandler) NULL)
4454 return((PixelPacket *) NULL);
4455 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4465 + R e a d P i x e l C a c h e I n d e x e s %
4469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4471 % ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4474 % The format of the ReadPixelCacheIndexes() method is:
4476 % MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4477 % NexusInfo *nexus_info,ExceptionInfo *exception)
4479 % A description of each parameter follows:
4481 % o cache_info: the pixel cache.
4483 % o nexus_info: the cache nexus to read the colormap indexes.
4485 % o exception: return any errors or warnings in this structure.
4488 static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4489 NexusInfo *nexus_info,ExceptionInfo *exception)
4499 register IndexPacket
4508 if (cache_info->debug != MagickFalse)
4509 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4510 cache_info->filename);
4511 if (cache_info->active_index_channel == MagickFalse)
4512 return(MagickFalse);
4513 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4515 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4516 nexus_info->region.x;
4517 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4518 rows=nexus_info->region.height;
4519 number_pixels=length*rows;
4520 if ((cache_info->columns == nexus_info->region.width) &&
4521 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4523 length=number_pixels;
4526 q=nexus_info->indexes;
4527 switch (cache_info->type)
4532 register IndexPacket
4536 Read indexes from memory.
4538 p=cache_info->indexes+offset;
4539 for (y=0; y < (long) rows; y++)
4541 (void) CopyMagickMemory(q,p,(size_t) length);
4542 p+=cache_info->columns;
4543 q+=nexus_info->region.width;
4550 Read indexes from disk.
4552 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4554 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4555 cache_info->cache_filename);
4556 return(MagickFalse);
4558 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4559 for (y=0; y < (long) rows; y++)
4561 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4562 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4563 if ((MagickSizeType) count < length)
4565 offset+=cache_info->columns;
4566 q+=nexus_info->region.width;
4568 if (y < (long) rows)
4570 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4571 cache_info->cache_filename);
4572 return(MagickFalse);
4579 if ((cache_info->debug != MagickFalse) &&
4580 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4581 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4582 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4583 nexus_info->region.x,nexus_info->region.y);
4588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4592 + R e a d P i x e l C a c h e P i x e l s %
4596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4598 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4601 % The format of the ReadPixelCachePixels() method is:
4603 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4604 % NexusInfo *nexus_info,ExceptionInfo *exception)
4606 % A description of each parameter follows:
4608 % o cache_info: the pixel cache.
4610 % o nexus_info: the cache nexus to read the pixels.
4612 % o exception: return any errors or warnings in this structure.
4615 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4616 NexusInfo *nexus_info,ExceptionInfo *exception)
4629 register PixelPacket
4635 if (cache_info->debug != MagickFalse)
4636 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4637 cache_info->filename);
4638 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4640 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4641 nexus_info->region.x;
4642 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4643 rows=nexus_info->region.height;
4644 number_pixels=length*rows;
4645 if ((cache_info->columns == nexus_info->region.width) &&
4646 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4648 length=number_pixels;
4651 q=nexus_info->pixels;
4652 switch (cache_info->type)
4657 register PixelPacket
4661 Read pixels from memory.
4663 p=cache_info->pixels+offset;
4664 for (y=0; y < (long) rows; y++)
4666 (void) CopyMagickMemory(q,p,(size_t) length);
4667 p+=cache_info->columns;
4668 q+=nexus_info->region.width;
4675 Read pixels from disk.
4677 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4679 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4680 cache_info->cache_filename);
4681 return(MagickFalse);
4683 for (y=0; y < (long) rows; y++)
4685 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4686 sizeof(*q),length,(unsigned char *) q);
4687 if ((MagickSizeType) count < length)
4689 offset+=cache_info->columns;
4690 q+=nexus_info->region.width;
4692 if (y < (long) rows)
4694 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4695 cache_info->cache_filename);
4696 return(MagickFalse);
4703 if ((cache_info->debug != MagickFalse) &&
4704 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4705 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
4706 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
4707 nexus_info->region.x,nexus_info->region.y);
4712 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4716 + R e f e r e n c e P i x e l C a c h e %
4720 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4722 % ReferencePixelCache() increments the reference count associated with the
4723 % pixel cache returning a pointer to the cache.
4725 % The format of the ReferencePixelCache method is:
4727 % Cache ReferencePixelCache(Cache cache_info)
4729 % A description of each parameter follows:
4731 % o cache_info: the pixel cache.
4734 MagickExport Cache ReferencePixelCache(Cache cache)
4739 assert(cache != (Cache *) NULL);
4740 cache_info=(CacheInfo *) cache;
4741 assert(cache_info->signature == MagickSignature);
4742 if (cache_info->debug != MagickFalse)
4743 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4744 cache_info->filename);
4745 (void) LockSemaphoreInfo(cache_info->semaphore);
4746 cache_info->reference_count++;
4747 (void) UnlockSemaphoreInfo(cache_info->semaphore);
4752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4756 + S e t P i x e l C a c h e M e t h o d s %
4760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4762 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4764 % The format of the SetPixelCacheMethods() method is:
4766 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4768 % A description of each parameter follows:
4770 % o cache: the pixel cache.
4772 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4775 MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4780 GetOneAuthenticPixelFromHandler
4781 get_one_authentic_pixel_from_handler;
4783 GetOneVirtualPixelFromHandler
4784 get_one_virtual_pixel_from_handler;
4787 Set cache pixel methods.
4789 assert(cache != (Cache) NULL);
4790 assert(cache_methods != (CacheMethods *) NULL);
4791 cache_info=(CacheInfo *) cache;
4792 assert(cache_info->signature == MagickSignature);
4793 if (cache_info->debug != MagickFalse)
4794 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4795 cache_info->filename);
4796 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4797 cache_info->methods.get_virtual_pixel_handler=
4798 cache_methods->get_virtual_pixel_handler;
4799 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4800 cache_info->methods.destroy_pixel_handler=
4801 cache_methods->destroy_pixel_handler;
4802 if (cache_methods->get_virtual_indexes_from_handler !=
4803 (GetVirtualIndexesFromHandler) NULL)
4804 cache_info->methods.get_virtual_indexes_from_handler=
4805 cache_methods->get_virtual_indexes_from_handler;
4806 if (cache_methods->get_authentic_pixels_handler !=
4807 (GetAuthenticPixelsHandler) NULL)
4808 cache_info->methods.get_authentic_pixels_handler=
4809 cache_methods->get_authentic_pixels_handler;
4810 if (cache_methods->queue_authentic_pixels_handler !=
4811 (QueueAuthenticPixelsHandler) NULL)
4812 cache_info->methods.queue_authentic_pixels_handler=
4813 cache_methods->queue_authentic_pixels_handler;
4814 if (cache_methods->sync_authentic_pixels_handler !=
4815 (SyncAuthenticPixelsHandler) NULL)
4816 cache_info->methods.sync_authentic_pixels_handler=
4817 cache_methods->sync_authentic_pixels_handler;
4818 if (cache_methods->get_authentic_pixels_from_handler !=
4819 (GetAuthenticPixelsFromHandler) NULL)
4820 cache_info->methods.get_authentic_pixels_from_handler=
4821 cache_methods->get_authentic_pixels_from_handler;
4822 if (cache_methods->get_authentic_indexes_from_handler !=
4823 (GetAuthenticIndexesFromHandler) NULL)
4824 cache_info->methods.get_authentic_indexes_from_handler=
4825 cache_methods->get_authentic_indexes_from_handler;
4826 get_one_virtual_pixel_from_handler=
4827 cache_info->methods.get_one_virtual_pixel_from_handler;
4828 if (get_one_virtual_pixel_from_handler !=
4829 (GetOneVirtualPixelFromHandler) NULL)
4830 cache_info->methods.get_one_virtual_pixel_from_handler=
4831 cache_methods->get_one_virtual_pixel_from_handler;
4832 get_one_authentic_pixel_from_handler=
4833 cache_methods->get_one_authentic_pixel_from_handler;
4834 if (get_one_authentic_pixel_from_handler !=
4835 (GetOneAuthenticPixelFromHandler) NULL)
4836 cache_info->methods.get_one_authentic_pixel_from_handler=
4837 cache_methods->get_one_authentic_pixel_from_handler;
4841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4845 + S e t P i x e l C a c h e N e x u s P i x e l s %
4849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4851 % SetPixelCacheNexusPixels() defines the region of the cache for the
4852 % specified cache nexus.
4854 % The format of the SetPixelCacheNexusPixels() method is:
4856 % PixelPacket SetPixelCacheNexusPixels(const Image *image,
4857 % const RectangleInfo *region,NexusInfo *nexus_info,
4858 % ExceptionInfo *exception)
4860 % A description of each parameter follows:
4862 % o image: the image.
4864 % o region: A pointer to the RectangleInfo structure that defines the
4865 % region of this particular cache nexus.
4867 % o nexus_info: the cache nexus to set.
4869 % o exception: return any errors or warnings in this structure.
4872 static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4873 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4888 if (image->debug != MagickFalse)
4889 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4890 cache_info=(CacheInfo *) image->cache;
4891 assert(cache_info->signature == MagickSignature);
4892 if (cache_info->type == UndefinedCache)
4893 return((PixelPacket *) NULL);
4894 nexus_info->region.width=region->width == 0UL ? 1UL : region->width;
4895 nexus_info->region.height=region->height == 0UL ? 1UL : region->height;
4896 nexus_info->region.x=region->x;
4897 nexus_info->region.y=region->y;
4898 if ((cache_info->type != DiskCache) && (image->clip_mask == (Image *) NULL) &&
4899 (image->mask == (Image *) NULL))
4901 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4902 nexus_info->region.x;
4903 length=(MagickSizeType) (nexus_info->region.height-1)*cache_info->columns+
4904 nexus_info->region.width-1;
4905 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4906 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
4912 x=nexus_info->region.x+nexus_info->region.width;
4913 y=nexus_info->region.y+nexus_info->region.height;
4914 if ((nexus_info->region.x >= 0) &&
4915 (x <= (long) cache_info->columns) &&
4916 (nexus_info->region.y >= 0) && (y <= (long) cache_info->rows))
4917 if ((nexus_info->region.height == 1UL) ||
4918 ((nexus_info->region.x == 0) &&
4919 ((nexus_info->region.width % cache_info->columns) == 0)))
4922 Pixels are accessed directly from memory.
4924 nexus_info->pixels=cache_info->pixels+offset;
4925 nexus_info->indexes=(IndexPacket *) NULL;
4926 if (cache_info->active_index_channel != MagickFalse)
4927 nexus_info->indexes=cache_info->indexes+offset;
4928 return(nexus_info->pixels);
4933 Pixels are stored in a cache region until they are synced to the cache.
4935 number_pixels=(MagickSizeType) nexus_info->region.width*
4936 nexus_info->region.height;
4937 length=number_pixels*sizeof(PixelPacket);
4938 if (cache_info->active_index_channel != MagickFalse)
4939 length+=number_pixels*sizeof(IndexPacket);
4940 if (nexus_info->cache == (PixelPacket *) NULL)
4942 nexus_info->length=length;
4943 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4944 if (status == MagickFalse)
4945 return((PixelPacket *) NULL);
4948 if (nexus_info->length != length)
4950 RelinquishCacheNexusPixels(nexus_info);
4951 nexus_info->length=length;
4952 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4953 if (status == MagickFalse)
4954 return((PixelPacket *) NULL);
4956 nexus_info->pixels=nexus_info->cache;
4957 nexus_info->indexes=(IndexPacket *) NULL;
4958 if (cache_info->active_index_channel != MagickFalse)
4959 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
4960 return(nexus_info->pixels);
4964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4968 % 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 %
4972 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4974 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
4975 % pixel cache and returns the previous setting. A virtual pixel is any pixel
4976 % access that is outside the boundaries of the image cache.
4978 % The format of the SetPixelCacheVirtualMethod() method is:
4980 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4981 % const VirtualPixelMethod virtual_pixel_method)
4983 % A description of each parameter follows:
4985 % o image: the image.
4987 % o virtual_pixel_method: choose the type of virtual pixel.
4990 MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
4991 const VirtualPixelMethod virtual_pixel_method)
4999 assert(image != (Image *) NULL);
5000 assert(image->signature == MagickSignature);
5001 if (image->debug != MagickFalse)
5002 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5003 assert(image->cache != (Cache) NULL);
5004 cache_info=(CacheInfo *) image->cache;
5005 assert(cache_info->signature == MagickSignature);
5006 method=cache_info->virtual_pixel_method;
5007 cache_info->virtual_pixel_method=virtual_pixel_method;
5012 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5016 + 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 %
5020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5022 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5023 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5024 % is synced, otherwise MagickFalse.
5026 % The format of the SyncAuthenticPixelCacheNexus() method is:
5028 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5029 % NexusInfo *nexus_info,ExceptionInfo *exception)
5031 % A description of each parameter follows:
5033 % o image: the image.
5035 % o nexus_info: the cache nexus to sync.
5037 % o exception: return any errors or warnings in this structure.
5040 MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5041 NexusInfo *nexus_info,ExceptionInfo *exception)
5050 Transfer pixels to the cache.
5052 assert(image != (Image *) NULL);
5053 assert(image->signature == MagickSignature);
5054 if (image->debug != MagickFalse)
5055 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5056 if (image->cache == (Cache) NULL)
5057 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5058 cache_info=(CacheInfo *) image->cache;
5059 if (cache_info->type == UndefinedCache)
5060 return(MagickFalse);
5061 if ((image->clip_mask != (Image *) NULL) &&
5062 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5063 return(MagickFalse);
5064 if ((image->mask != (Image *) NULL) &&
5065 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5066 return(MagickFalse);
5067 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5069 assert(cache_info->signature == MagickSignature);
5070 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5071 if ((cache_info->active_index_channel != MagickFalse) &&
5072 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5073 return(MagickFalse);
5078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5082 + S y n c A u t h e n t i c P i x e l C a c h e %
5086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5088 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5089 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5090 % otherwise MagickFalse.
5092 % The format of the SyncAuthenticPixelsCache() method is:
5094 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5095 % ExceptionInfo *exception)
5097 % A description of each parameter follows:
5099 % o image: the image.
5101 % o exception: return any errors or warnings in this structure.
5104 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5105 ExceptionInfo *exception)
5116 cache_info=(CacheInfo *) image->cache;
5117 id=GetOpenMPThreadId();
5118 assert(id < (long) cache_info->number_threads);
5119 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5129 % S y n c A u t h e n t i c P i x e l s %
5133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5135 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5136 % The method returns MagickTrue if the pixel region is flushed, otherwise
5139 % The format of the SyncAuthenticPixels() method is:
5141 % MagickBooleanType SyncAuthenticPixels(Image *image,
5142 % ExceptionInfo *exception)
5144 % A description of each parameter follows:
5146 % o image: the image.
5148 % o exception: return any errors or warnings in this structure.
5151 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5152 ExceptionInfo *exception)
5157 assert(image != (Image *) NULL);
5158 assert(image->signature == MagickSignature);
5159 if (image->debug != MagickFalse)
5160 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5161 assert(image->cache != (Cache) NULL);
5162 cache_info=(CacheInfo *) image->cache;
5163 assert(cache_info->signature == MagickSignature);
5164 if (cache_info->methods.sync_authentic_pixels_handler ==
5165 (SyncAuthenticPixelsHandler) NULL)
5166 return(MagickFalse);
5167 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5175 + W r i t e P i x e l C a c h e I n d e x e s %
5179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5181 % WritePixelCacheIndexes() writes the colormap indexes to the specified
5182 % region of the pixel cache.
5184 % The format of the WritePixelCacheIndexes() method is:
5186 % MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5187 % NexusInfo *nexus_info,ExceptionInfo *exception)
5189 % A description of each parameter follows:
5191 % o cache_info: the pixel cache.
5193 % o nexus_info: the cache nexus to write the colormap indexes.
5195 % o exception: return any errors or warnings in this structure.
5198 static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5199 NexusInfo *nexus_info,ExceptionInfo *exception)
5209 register const IndexPacket
5218 if (cache_info->debug != MagickFalse)
5219 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5220 cache_info->filename);
5221 if (cache_info->active_index_channel == MagickFalse)
5222 return(MagickFalse);
5223 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5225 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5226 nexus_info->region.x;
5227 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5228 rows=nexus_info->region.height;
5229 number_pixels=(MagickSizeType) length*rows;
5230 if ((cache_info->columns == nexus_info->region.width) &&
5231 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5233 length=number_pixels;
5236 p=nexus_info->indexes;
5237 switch (cache_info->type)
5242 register IndexPacket
5246 Write indexes to memory.
5248 q=cache_info->indexes+offset;
5249 for (y=0; y < (long) rows; y++)
5251 (void) CopyMagickMemory(q,p,(size_t) length);
5252 p+=nexus_info->region.width;
5253 q+=cache_info->columns;
5260 Write indexes to disk.
5262 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5264 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5265 cache_info->cache_filename);
5266 return(MagickFalse);
5268 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5269 for (y=0; y < (long) rows; y++)
5271 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5272 sizeof(PixelPacket)+offset*sizeof(*p),length,
5273 (const unsigned char *) p);
5274 if ((MagickSizeType) count < length)
5276 p+=nexus_info->region.width;
5277 offset+=cache_info->columns;
5279 if (y < (long) rows)
5281 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5282 cache_info->cache_filename);
5283 return(MagickFalse);
5290 if ((cache_info->debug != MagickFalse) &&
5291 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5292 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5293 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5294 nexus_info->region.x,nexus_info->region.y);
5299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5303 + W r i t e C a c h e P i x e l s %
5307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5309 % WritePixelCachePixels() writes image pixels to the specified region of the
5312 % The format of the WritePixelCachePixels() method is:
5314 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5315 % NexusInfo *nexus_info,ExceptionInfo *exception)
5317 % A description of each parameter follows:
5319 % o cache_info: the pixel cache.
5321 % o nexus_info: the cache nexus to write the pixels.
5323 % o exception: return any errors or warnings in this structure.
5326 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5327 NexusInfo *nexus_info,ExceptionInfo *exception)
5340 register const PixelPacket
5346 if (cache_info->debug != MagickFalse)
5347 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5348 cache_info->filename);
5349 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5351 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5352 nexus_info->region.x;
5353 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5354 rows=nexus_info->region.height;
5355 number_pixels=length*rows;
5356 if ((cache_info->columns == nexus_info->region.width) &&
5357 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5359 length=number_pixels;
5362 p=nexus_info->pixels;
5363 switch (cache_info->type)
5368 register PixelPacket
5372 Write pixels to memory.
5374 q=cache_info->pixels+offset;
5375 for (y=0; y < (long) rows; y++)
5377 (void) CopyMagickMemory(q,p,(size_t) length);
5378 p+=nexus_info->region.width;
5379 q+=cache_info->columns;
5386 Write pixels to disk.
5388 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5390 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5391 cache_info->cache_filename);
5392 return(MagickFalse);
5394 for (y=0; y < (long) rows; y++)
5396 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5397 sizeof(*p),length,(const unsigned char *) p);
5398 if ((MagickSizeType) count < length)
5400 p+=nexus_info->region.width;
5401 offset+=cache_info->columns;
5403 if (y < (long) rows)
5405 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5406 cache_info->cache_filename);
5407 return(MagickFalse);
5414 if ((cache_info->debug != MagickFalse) &&
5415 (QuantumTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5416 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s[%lux%lu%+ld%+ld]",
5417 cache_info->filename,nexus_info->region.width,nexus_info->region.height,
5418 nexus_info->region.x,nexus_info->region.y);