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-2010 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/geometry.h"
53 #include "magick/list.h"
54 #include "magick/log.h"
55 #include "magick/magick.h"
56 #include "magick/memory_.h"
57 #include "magick/pixel.h"
58 #include "magick/pixel-private.h"
59 #include "magick/policy.h"
60 #include "magick/quantum.h"
61 #include "magick/random_.h"
62 #include "magick/resource_.h"
63 #include "magick/semaphore.h"
64 #include "magick/splay-tree.h"
65 #include "magick/string_.h"
66 #include "magick/string-private.h"
67 #include "magick/thread-private.h"
68 #include "magick/utility.h"
69 #if defined(MAGICKCORE_ZLIB_DELEGATE)
76 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
81 typedef struct _MagickModulo
111 Forward declarations.
113 #if defined(__cplusplus) || defined(c_plusplus)
117 static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
120 static const PixelPacket
121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
123 *GetVirtualPixelsCache(const Image *);
125 static MagickBooleanType
126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
145 #if defined(__cplusplus) || defined(c_plusplus)
152 static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
156 *cache_semaphore = (SemaphoreInfo *) NULL;
159 *cache_resources = (SplayTreeInfo *) NULL;
162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166 + A c q u i r e P i x e l C a c h e %
170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 % AcquirePixelCache() acquires a pixel cache.
174 % The format of the AcquirePixelCache() method is:
176 % Cache AcquirePixelCache(const size_t number_threads)
178 % A description of each parameter follows:
180 % o number_threads: the number of nexus threads.
183 MagickExport Cache AcquirePixelCache(const size_t number_threads)
188 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
193 cache_info->mode=IOMode;
194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
203 GetPixelCacheMethods(&cache_info->methods);
204 cache_info->semaphore=AllocateSemaphoreInfo();
205 cache_info->reference_count=1;
206 cache_info->disk_semaphore=AllocateSemaphoreInfo();
207 cache_info->debug=IsEventLogging();
208 cache_info->signature=MagickSignature;
209 if ((cache_resources == (SplayTreeInfo *) NULL) &&
210 (instantiate_cache == MagickFalse))
212 if (cache_semaphore == (SemaphoreInfo *) NULL)
213 AcquireSemaphoreInfo(&cache_semaphore);
214 LockSemaphoreInfo(cache_semaphore);
215 if ((cache_resources == (SplayTreeInfo *) NULL) &&
216 (instantiate_cache == MagickFalse))
218 cache_resources=NewSplayTree((int (*)(const void *,const void *))
219 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
220 instantiate_cache=MagickTrue;
222 UnlockSemaphoreInfo(cache_semaphore);
224 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
225 return((Cache ) cache_info);
229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 % A c q u i r e P i x e l C a c h e N e x u s %
237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
241 % The format of the AcquirePixelCacheNexus method is:
243 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
245 % A description of each parameter follows:
247 % o number_threads: the number of nexus threads.
250 MagickExport NexusInfo **AcquirePixelCacheNexus(
251 const size_t number_threads)
259 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
260 sizeof(*nexus_info));
261 if (nexus_info == (NexusInfo **) NULL)
262 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
263 for (i=0; i < (ssize_t) number_threads; i++)
265 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
266 if (nexus_info[i] == (NexusInfo *) NULL)
267 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
268 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
269 nexus_info[i]->signature=MagickSignature;
275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279 + A c q u i r e P i x e l C a c h e P i x e l s %
283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
285 % AcquirePixelCachePixels() returns the pixels associated with the specified
288 % The format of the AcquirePixelCachePixels() method is:
290 % const void *AcquirePixelCachePixels(const Image *image,
291 % MagickSizeType *length,ExceptionInfo *exception)
293 % A description of each parameter follows:
295 % o image: the image.
297 % o length: the pixel cache length.
299 % o exception: return any errors or warnings in this structure.
302 MagickExport const void *AcquirePixelCachePixels(const Image *image,
303 MagickSizeType *length,ExceptionInfo *exception)
308 assert(image != (const Image *) NULL);
309 assert(image->signature == MagickSignature);
310 assert(exception != (ExceptionInfo *) NULL);
311 assert(exception->signature == MagickSignature);
312 assert(image->cache != (Cache) NULL);
313 cache_info=(CacheInfo *) image->cache;
314 assert(cache_info->signature == MagickSignature);
316 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
317 return((const void *) NULL);
318 *length=cache_info->length;
319 return((const void *) cache_info->pixels);
323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327 + C a c h e C o m p o n e n t G e n e s i s %
331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333 % CacheComponentGenesis() instantiates the cache component.
335 % The format of the CacheComponentGenesis method is:
337 % MagickBooleanType CacheComponentGenesis(void)
340 MagickExport MagickBooleanType CacheComponentGenesis(void)
342 AcquireSemaphoreInfo(&cache_semaphore);
347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351 + C a c h e C o m p o n e n t T e r m i n u s %
355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357 % CacheComponentTerminus() destroys the cache component.
359 % The format of the CacheComponentTerminus() method is:
361 % CacheComponentTerminus(void)
364 MagickExport void CacheComponentTerminus(void)
366 if (cache_semaphore == (SemaphoreInfo *) NULL)
367 AcquireSemaphoreInfo(&cache_semaphore);
368 LockSemaphoreInfo(cache_semaphore);
369 if (cache_resources != (SplayTreeInfo *) NULL)
370 cache_resources=DestroySplayTree(cache_resources);
371 instantiate_cache=MagickFalse;
372 UnlockSemaphoreInfo(cache_semaphore);
373 DestroySemaphoreInfo(&cache_semaphore);
377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381 + C l i p P i x e l C a c h e N e x u s %
385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
387 % ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
388 % mask. The method returns MagickTrue if the pixel region is clipped,
389 % otherwise MagickFalse.
391 % The format of the ClipPixelCacheNexus() method is:
393 % MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
394 % ExceptionInfo *exception)
396 % A description of each parameter follows:
398 % o image: the image.
400 % o nexus_info: the cache nexus to clip.
402 % o exception: return any errors or warnings in this structure.
405 static MagickBooleanType ClipPixelCacheNexus(Image *image,
406 NexusInfo *nexus_info,ExceptionInfo *exception)
418 register const PixelPacket
422 *restrict nexus_indexes,
435 if (image->debug != MagickFalse)
436 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
437 if (image->clip_mask == (Image *) NULL)
439 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
440 if (cache_info == (Cache) NULL)
442 image_nexus=AcquirePixelCacheNexus(1);
443 clip_nexus=AcquirePixelCacheNexus(1);
444 if ((image_nexus == (NexusInfo **) NULL) ||
445 (clip_nexus == (NexusInfo **) NULL))
446 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
447 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
448 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
450 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
451 q=nexus_info->pixels;
452 nexus_indexes=nexus_info->indexes;
453 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
454 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
455 nexus_info->region.height,clip_nexus[0],exception);
456 number_pixels=(MagickSizeType) nexus_info->region.width*
457 nexus_info->region.height;
458 for (i=0; i < (ssize_t) number_pixels; i++)
460 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
462 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
464 SetRedPixelComponent(q,GetRedPixelComponent(p));
465 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
466 SetBluePixelComponent(q,GetBluePixelComponent(p));
467 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
468 if (cache_info->active_index_channel != MagickFalse)
469 nexus_indexes[i]=indexes[i];
475 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
476 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
477 if (i < (ssize_t) number_pixels)
483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
487 + C l o n e P i x e l C a c h e %
491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493 % ClonePixelCache() clones a pixel cache.
495 % The format of the ClonePixelCache() method is:
497 % Cache ClonePixelCache(const Cache cache)
499 % A description of each parameter follows:
501 % o cache: the pixel cache.
504 MagickExport Cache ClonePixelCache(const Cache cache)
512 assert(cache != (const Cache) NULL);
513 cache_info=(const CacheInfo *) cache;
514 assert(cache_info->signature == MagickSignature);
515 if (cache_info->debug != MagickFalse)
516 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
517 cache_info->filename);
518 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
519 if (clone_info == (Cache) NULL)
520 return((Cache) NULL);
521 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
522 return((Cache ) clone_info);
526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
530 + C l o n e P i x e l C a c h e N e x u s %
534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
536 % ClonePixelCacheNexus() clones the source cache nexus to the destination
539 % The format of the ClonePixelCacheNexus() method is:
541 % MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
542 % CacheInfo *source,ExceptionInfo *exception)
544 % A description of each parameter follows:
546 % o destination: the destination cache nexus.
548 % o source: the source cache nexus.
550 % o exception: return any errors or warnings in this structure.
554 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
555 NexusInfo *nexus_info,ExceptionInfo *exception)
557 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
559 nexus_info->mapped=MagickFalse;
560 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
562 if (nexus_info->cache == (PixelPacket *) NULL)
564 nexus_info->mapped=MagickTrue;
565 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
568 if (nexus_info->cache == (PixelPacket *) NULL)
570 (void) ThrowMagickException(exception,GetMagickModule(),
571 ResourceLimitError,"MemoryAllocationFailed","`%s'",
572 cache_info->filename);
578 static MagickBooleanType ClonePixelCacheNexus(CacheInfo *destination,
579 CacheInfo *source,ExceptionInfo *exception)
587 register const NexusInfo
597 for (i=0; i < (ssize_t) source->number_threads; i++)
599 p=source->nexus_info[i];
600 q=destination->nexus_info[i];
606 q->indexes=p->indexes;
607 if (p->cache != (PixelPacket *) NULL)
609 status=AcquireCacheNexusPixels(source,q,exception);
610 if (status != MagickFalse)
612 (void) CopyMagickMemory(q->cache,p->cache,(size_t) p->length);
614 q->indexes=(IndexPacket *) NULL;
615 number_pixels=(MagickSizeType) q->region.width*q->region.height;
616 if (p->indexes != (IndexPacket *) NULL)
617 q->indexes=(IndexPacket *) (q->pixels+number_pixels);
625 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629 + C l o n e P i x e l C a c h e P i x e l s %
633 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
634 % ClonePixelCachePixels() clones the source pixel cache to the destination
637 % The format of the ClonePixelCachePixels() method is:
639 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
640 % CacheInfo *source_info,ExceptionInfo *exception)
642 % A description of each parameter follows:
644 % o cache_info: the pixel cache.
646 % o source_info: the source pixel cache.
648 % o exception: return any errors or warnings in this structure.
652 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
658 LockSemaphoreInfo(cache_info->disk_semaphore);
659 if (cache_info->file != -1)
660 status=close(cache_info->file);
661 cache_info->file=(-1);
662 RelinquishMagickResource(FileResource,1);
663 UnlockSemaphoreInfo(cache_info->disk_semaphore);
664 return(status == -1 ? MagickFalse : MagickTrue);
667 static void LimitPixelCacheDescriptors(void)
674 Limit # of open file descriptors.
676 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
678 LockSemaphoreInfo(cache_semaphore);
679 if (cache_resources == (SplayTreeInfo *) NULL)
681 UnlockSemaphoreInfo(cache_semaphore);
684 ResetSplayTreeIterator(cache_resources);
685 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
686 while (p != (CacheInfo *) NULL)
688 if ((p->type == DiskCache) && (p->file != -1))
690 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
692 for (q=p; p != (CacheInfo *) NULL; )
694 if ((p->type == DiskCache) && (p->file != -1) &&
695 (p->timestamp < q->timestamp))
697 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
699 if (q != (CacheInfo *) NULL)
702 Close least recently used cache.
704 (void) close(q->file);
707 UnlockSemaphoreInfo(cache_semaphore);
710 static inline MagickSizeType MagickMax(const MagickSizeType x,
711 const MagickSizeType y)
718 static inline MagickSizeType MagickMin(const MagickSizeType x,
719 const MagickSizeType y)
726 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
733 Open pixel cache on disk.
735 LockSemaphoreInfo(cache_info->disk_semaphore);
736 if (cache_info->file != -1)
738 UnlockSemaphoreInfo(cache_info->disk_semaphore);
739 return(MagickTrue); /* cache already open */
741 LimitPixelCacheDescriptors();
742 if (*cache_info->cache_filename == '\0')
743 file=AcquireUniqueFileResource(cache_info->cache_filename);
749 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
754 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
757 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
763 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
766 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
772 UnlockSemaphoreInfo(cache_info->disk_semaphore);
775 (void) AcquireMagickResource(FileResource,1);
776 cache_info->file=file;
777 cache_info->timestamp=time(0);
778 UnlockSemaphoreInfo(cache_info->disk_semaphore);
782 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
783 const MagickOffsetType offset,const MagickSizeType length,
784 unsigned char *restrict buffer)
786 register MagickOffsetType
792 cache_info->timestamp=time(0);
793 #if !defined(MAGICKCORE_HAVE_PREAD)
794 LockSemaphoreInfo(cache_info->disk_semaphore);
795 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
797 UnlockSemaphoreInfo(cache_info->disk_semaphore);
798 return((MagickOffsetType) -1);
802 for (i=0; i < (MagickOffsetType) length; i+=count)
804 #if !defined(MAGICKCORE_HAVE_PREAD)
805 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
806 (MagickSizeType) SSIZE_MAX));
808 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
809 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
820 #if !defined(MAGICKCORE_HAVE_PREAD)
821 UnlockSemaphoreInfo(cache_info->disk_semaphore);
826 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
827 const MagickOffsetType offset,const MagickSizeType length,
828 const unsigned char *restrict buffer)
830 register MagickOffsetType
836 cache_info->timestamp=time(0);
837 #if !defined(MAGICKCORE_HAVE_PWRITE)
838 LockSemaphoreInfo(cache_info->disk_semaphore);
839 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
841 UnlockSemaphoreInfo(cache_info->disk_semaphore);
842 return((MagickOffsetType) -1);
846 for (i=0; i < (MagickOffsetType) length; i+=count)
848 #if !defined(MAGICKCORE_HAVE_PWRITE)
849 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
850 (MagickSizeType) SSIZE_MAX));
852 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
853 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
864 #if !defined(MAGICKCORE_HAVE_PWRITE)
865 UnlockSemaphoreInfo(cache_info->disk_semaphore);
870 static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
871 CacheInfo *cache_info,ExceptionInfo *exception)
891 if (cache_info->debug != MagickFalse)
892 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
893 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
895 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
896 clone_info->cache_filename);
899 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
901 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
902 cache_info->cache_filename);
905 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
906 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
907 if ((clone_info->active_index_channel != MagickFalse) &&
908 (cache_info->active_index_channel != MagickFalse))
916 length=MagickMax(clone_info->columns,cache_info->columns)*
918 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
919 if (indexes == (IndexPacket *) NULL)
921 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
922 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
925 (void) ResetMagickMemory(indexes,0,(size_t) length);
926 length=columns*sizeof(*indexes);
927 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
928 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
929 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
930 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
931 for (y=0; y < (ssize_t) rows; y++)
933 source_offset-=cache_info->columns*sizeof(*indexes);
934 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
935 length,(unsigned char *) indexes);
936 if ((MagickSizeType) count != length)
938 offset-=clone_info->columns*sizeof(*indexes);
939 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
940 (unsigned char *) indexes);
941 if ((MagickSizeType) count != length)
944 if (y < (ssize_t) rows)
946 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
947 ThrowFileException(exception,CacheError,"UnableToCloneCache",
948 cache_info->cache_filename);
951 if (clone_info->columns > cache_info->columns)
953 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
954 (void) ResetMagickMemory(indexes,0,(size_t) length);
955 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
956 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
957 for (y=0; y < (ssize_t) rows; y++)
959 offset-=clone_info->columns*sizeof(*indexes);
960 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
961 length,(unsigned char *) indexes);
962 if ((MagickSizeType) count != length)
965 if (y < (ssize_t) rows)
967 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
968 ThrowFileException(exception,CacheError,"UnableToCloneCache",
969 cache_info->cache_filename);
973 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
978 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
979 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
980 if (pixels == (PixelPacket *) NULL)
982 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
983 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
986 (void) ResetMagickMemory(pixels,0,(size_t) length);
987 length=columns*sizeof(*pixels);
988 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
989 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
990 for (y=0; y < (ssize_t) rows; y++)
992 source_offset-=cache_info->columns*sizeof(*pixels);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
994 length,(unsigned char *) pixels);
995 if ((MagickSizeType) count != length)
997 offset-=clone_info->columns*sizeof(*pixels);
998 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
999 (unsigned char *) pixels);
1000 if ((MagickSizeType) count != length)
1003 if (y < (ssize_t) rows)
1005 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1006 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1007 cache_info->cache_filename);
1008 return(MagickFalse);
1010 if (clone_info->columns > cache_info->columns)
1012 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1014 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1015 (void) ResetMagickMemory(pixels,0,(size_t) length);
1016 for (y=0; y < (ssize_t) rows; y++)
1018 offset-=clone_info->columns*sizeof(*pixels);
1019 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1020 (unsigned char *) pixels);
1021 if ((MagickSizeType) count != length)
1024 if (y < (ssize_t) rows)
1026 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1027 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1028 cache_info->cache_filename);
1029 return(MagickFalse);
1032 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1036 static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
1037 CacheInfo *cache_info,ExceptionInfo *exception)
1046 register PixelPacket
1057 if (cache_info->debug != MagickFalse)
1058 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
1059 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
1061 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1062 cache_info->cache_filename);
1063 return(MagickFalse);
1065 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1066 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1067 if ((clone_info->active_index_channel != MagickFalse) &&
1068 (cache_info->active_index_channel != MagickFalse))
1070 register IndexPacket
1075 Clone cache indexes.
1077 length=MagickMax(clone_info->columns,cache_info->columns)*
1079 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1080 if (indexes == (IndexPacket *) NULL)
1082 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1083 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1084 return(MagickFalse);
1086 (void) ResetMagickMemory(indexes,0,(size_t) length);
1087 length=columns*sizeof(IndexPacket);
1088 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
1089 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
1090 q=clone_info->indexes+clone_info->columns*rows;
1091 for (y=0; y < (ssize_t) rows; y++)
1093 offset-=cache_info->columns*sizeof(IndexPacket);
1094 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
1095 length,(unsigned char *) indexes);
1096 if ((MagickSizeType) count != length)
1098 q-=clone_info->columns;
1099 (void) CopyMagickMemory(q,indexes,(size_t) length);
1100 if ((MagickSizeType) count != length)
1103 if (y < (ssize_t) rows)
1105 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1106 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1107 cache_info->cache_filename);
1108 return(MagickFalse);
1110 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1116 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1117 if (pixels == (PixelPacket *) NULL)
1119 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1120 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1121 return(MagickFalse);
1123 (void) ResetMagickMemory(pixels,0,(size_t) length);
1124 length=columns*sizeof(*pixels);
1125 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1126 q=clone_info->pixels+clone_info->columns*rows;
1127 for (y=0; y < (ssize_t) rows; y++)
1129 offset-=cache_info->columns*sizeof(*pixels);
1130 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1131 (unsigned char *) pixels);
1132 if ((MagickSizeType) count != length)
1134 q-=clone_info->columns;
1135 (void) CopyMagickMemory(q,pixels,(size_t) length);
1137 if (y < (ssize_t) rows)
1139 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1140 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1141 cache_info->cache_filename);
1142 return(MagickFalse);
1144 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1148 static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1149 CacheInfo *cache_info,ExceptionInfo *exception)
1158 register PixelPacket
1169 if (cache_info->debug != MagickFalse)
1170 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1171 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1173 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1174 clone_info->cache_filename);
1175 return(MagickFalse);
1177 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1178 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1179 if ((clone_info->active_index_channel != MagickFalse) &&
1180 (cache_info->active_index_channel != MagickFalse))
1182 register IndexPacket
1187 Clone cache indexes.
1189 length=MagickMax(clone_info->columns,cache_info->columns)*
1191 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1192 if (indexes == (IndexPacket *) NULL)
1194 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1195 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1196 return(MagickFalse);
1198 (void) ResetMagickMemory(indexes,0,(size_t) length);
1199 length=columns*sizeof(*indexes);
1200 p=cache_info->indexes+cache_info->columns*rows;
1201 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1202 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
1203 for (y=0; y < (ssize_t) rows; y++)
1205 p-=cache_info->columns;
1206 (void) CopyMagickMemory(indexes,p,(size_t) length);
1207 offset-=clone_info->columns*sizeof(*indexes);
1208 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1209 (unsigned char *) indexes);
1210 if ((MagickSizeType) count != length)
1213 if (y < (ssize_t) rows)
1215 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1216 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1217 cache_info->cache_filename);
1218 return(MagickFalse);
1220 if (clone_info->columns > cache_info->columns)
1222 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1223 (void) ResetMagickMemory(indexes,0,(size_t) length);
1224 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1225 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
1226 for (y=0; y < (ssize_t) rows; y++)
1228 offset-=clone_info->columns*sizeof(*indexes);
1229 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1230 length,(unsigned char *) indexes);
1231 if ((MagickSizeType) count != length)
1234 if (y < (ssize_t) rows)
1236 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1237 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1238 cache_info->cache_filename);
1239 return(MagickFalse);
1242 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1247 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1248 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1249 if (pixels == (PixelPacket *) NULL)
1251 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1252 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1253 return(MagickFalse);
1255 (void) ResetMagickMemory(pixels,0,(size_t) length);
1256 length=columns*sizeof(*pixels);
1257 p=cache_info->pixels+cache_info->columns*rows;
1258 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
1259 for (y=0; y < (ssize_t) rows; y++)
1261 p-=cache_info->columns;
1262 (void) CopyMagickMemory(pixels,p,(size_t) length);
1263 offset-=clone_info->columns*sizeof(*pixels);
1264 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1265 (unsigned char *) pixels);
1266 if ((MagickSizeType) count != length)
1269 if (y < (ssize_t) rows)
1271 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1272 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1273 cache_info->cache_filename);
1274 return(MagickFalse);
1276 if (clone_info->columns > cache_info->columns)
1278 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1280 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1281 (void) ResetMagickMemory(pixels,0,(size_t) length);
1282 for (y=0; y < (ssize_t) rows; y++)
1284 offset-=clone_info->columns*sizeof(*pixels);
1285 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1286 (unsigned char *) pixels);
1287 if ((MagickSizeType) count != length)
1290 if (y < (ssize_t) rows)
1292 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1293 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1294 cache_info->cache_filename);
1295 return(MagickFalse);
1298 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1302 static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1303 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1305 register PixelPacket
1307 *restrict source_pixels;
1317 if (cache_info->debug != MagickFalse)
1318 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
1319 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1320 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1321 if ((clone_info->active_index_channel != MagickFalse) &&
1322 (cache_info->active_index_channel != MagickFalse))
1324 register IndexPacket
1329 Clone cache indexes.
1331 length=columns*sizeof(*indexes);
1332 if (clone_info->columns == cache_info->columns)
1333 (void) CopyMagickMemory(clone_info->indexes,cache_info->indexes,
1337 source_indexes=cache_info->indexes+cache_info->columns*rows;
1338 indexes=clone_info->indexes+clone_info->columns*rows;
1339 for (y=0; y < (ssize_t) rows; y++)
1341 source_indexes-=cache_info->columns;
1342 indexes-=clone_info->columns;
1343 (void) CopyMagickMemory(indexes,source_indexes,length);
1345 if (clone_info->columns > cache_info->columns)
1347 length=(clone_info->columns-cache_info->columns)*
1349 indexes=clone_info->indexes+clone_info->columns*rows+
1350 cache_info->columns;
1351 for (y=0; y < (ssize_t) rows; y++)
1353 indexes-=clone_info->columns;
1354 (void) ResetMagickMemory(indexes,0,length);
1362 length=columns*sizeof(*pixels);
1363 if (clone_info->columns == cache_info->columns)
1364 (void) CopyMagickMemory(clone_info->pixels,cache_info->pixels,length*rows);
1367 source_pixels=cache_info->pixels+cache_info->columns*rows;
1368 pixels=clone_info->pixels+clone_info->columns*rows;
1369 for (y=0; y < (ssize_t) rows; y++)
1371 source_pixels-=cache_info->columns;
1372 pixels-=clone_info->columns;
1373 (void) CopyMagickMemory(pixels,source_pixels,length);
1375 if (clone_info->columns > cache_info->columns)
1377 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1378 pixels=clone_info->pixels+clone_info->columns*rows+
1379 cache_info->columns;
1380 for (y=0; y < (ssize_t) rows; y++)
1382 pixels-=clone_info->columns;
1383 (void) ResetMagickMemory(pixels,0,length);
1390 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1391 CacheInfo *cache_info,ExceptionInfo *exception)
1393 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1394 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1395 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1396 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1397 if (cache_info->type == DiskCache)
1398 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1399 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1407 + C l o n e P i x e l C a c h e M e t h o d s %
1411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1413 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1416 % The format of the ClonePixelCacheMethods() method is:
1418 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1420 % A description of each parameter follows:
1422 % o clone: Specifies a pointer to a Cache structure.
1424 % o cache: the pixel cache.
1427 MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1433 assert(clone != (Cache) NULL);
1434 source_info=(CacheInfo *) clone;
1435 assert(source_info->signature == MagickSignature);
1436 if (source_info->debug != MagickFalse)
1437 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1438 source_info->filename);
1439 assert(cache != (Cache) NULL);
1440 cache_info=(CacheInfo *) cache;
1441 assert(cache_info->signature == MagickSignature);
1442 source_info->methods=cache_info->methods;
1446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1450 + D e s t r o y I m a g e P i x e l C a c h e %
1454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1456 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1458 % The format of the DestroyImagePixelCache() method is:
1460 % void DestroyImagePixelCache(Image *image)
1462 % A description of each parameter follows:
1464 % o image: the image.
1467 static void DestroyImagePixelCache(Image *image)
1469 assert(image != (Image *) NULL);
1470 assert(image->signature == MagickSignature);
1471 if (image->debug != MagickFalse)
1472 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1473 if (image->cache == (void *) NULL)
1475 image->cache=DestroyPixelCache(image->cache);
1479 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1483 + D e s t r o y I m a g e P i x e l s %
1487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1489 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1491 % The format of the DestroyImagePixels() method is:
1493 % void DestroyImagePixels(Image *image)
1495 % A description of each parameter follows:
1497 % o image: the image.
1500 MagickExport void DestroyImagePixels(Image *image)
1505 assert(image != (const Image *) NULL);
1506 assert(image->signature == MagickSignature);
1507 if (image->debug != MagickFalse)
1508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1509 assert(image->cache != (Cache) NULL);
1510 cache_info=(CacheInfo *) image->cache;
1511 assert(cache_info->signature == MagickSignature);
1512 if (cache_info->methods.destroy_pixel_handler == (DestroyPixelHandler) NULL)
1514 cache_info->methods.destroy_pixel_handler(image);
1518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1522 + D e s t r o y P i x e l C a c h e %
1526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1528 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1530 % The format of the DestroyPixelCache() method is:
1532 % Cache DestroyPixelCache(Cache cache)
1534 % A description of each parameter follows:
1536 % o cache: the pixel cache.
1540 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1542 switch (cache_info->type)
1546 if (cache_info->mapped == MagickFalse)
1547 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1548 cache_info->pixels);
1550 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1551 (size_t) cache_info->length);
1552 RelinquishMagickResource(MemoryResource,cache_info->length);
1557 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1558 cache_info->length);
1559 RelinquishMagickResource(MapResource,cache_info->length);
1563 if (cache_info->file != -1)
1564 (void) ClosePixelCacheOnDisk(cache_info);
1565 RelinquishMagickResource(DiskResource,cache_info->length);
1571 cache_info->type=UndefinedCache;
1572 cache_info->mapped=MagickFalse;
1573 cache_info->indexes=(IndexPacket *) NULL;
1576 MagickExport Cache DestroyPixelCache(Cache cache)
1581 assert(cache != (Cache) NULL);
1582 cache_info=(CacheInfo *) cache;
1583 assert(cache_info->signature == MagickSignature);
1584 if (cache_info->debug != MagickFalse)
1585 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1586 cache_info->filename);
1587 LockSemaphoreInfo(cache_info->semaphore);
1588 cache_info->reference_count--;
1589 if (cache_info->reference_count != 0)
1591 UnlockSemaphoreInfo(cache_info->semaphore);
1592 return((Cache) NULL);
1594 UnlockSemaphoreInfo(cache_info->semaphore);
1595 if (cache_resources != (SplayTreeInfo *) NULL)
1596 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1597 if (cache_info->debug != MagickFalse)
1600 message[MaxTextExtent];
1602 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1603 cache_info->filename);
1604 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1606 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1607 (cache_info->type != DiskCache)))
1608 RelinquishPixelCachePixels(cache_info);
1611 RelinquishPixelCachePixels(cache_info);
1612 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1614 *cache_info->cache_filename='\0';
1615 if (cache_info->nexus_info != (NexusInfo **) NULL)
1616 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1617 cache_info->number_threads);
1618 if (cache_info->random_info != (RandomInfo *) NULL)
1619 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1620 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1621 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1622 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1623 DestroySemaphoreInfo(&cache_info->semaphore);
1624 cache_info->signature=(~MagickSignature);
1625 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1635 + D e s t r o y P i x e l C a c h e N e x u s %
1639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1641 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1643 % The format of the DestroyPixelCacheNexus() method is:
1645 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1646 % const size_t number_threads)
1648 % A description of each parameter follows:
1650 % o nexus_info: the nexus to destroy.
1652 % o number_threads: the number of nexus threads.
1656 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1658 if (nexus_info->mapped == MagickFalse)
1659 (void) RelinquishMagickMemory(nexus_info->cache);
1661 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1662 nexus_info->cache=(PixelPacket *) NULL;
1663 nexus_info->pixels=(PixelPacket *) NULL;
1664 nexus_info->indexes=(IndexPacket *) NULL;
1665 nexus_info->length=0;
1666 nexus_info->mapped=MagickFalse;
1669 MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1670 const size_t number_threads)
1675 assert(nexus_info != (NexusInfo **) NULL);
1676 for (i=0; i < (ssize_t) number_threads; i++)
1678 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1679 RelinquishCacheNexusPixels(nexus_info[i]);
1680 nexus_info[i]->signature=(~MagickSignature);
1681 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1683 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1692 + 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 %
1696 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1698 % GetAuthenticIndexesFromCache() returns the indexes associated with the last
1699 % call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1701 % The format of the GetAuthenticIndexesFromCache() method is:
1703 % IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1705 % A description of each parameter follows:
1707 % o image: the image.
1710 static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1721 cache_info=(CacheInfo *) image->cache;
1722 id=GetOpenMPThreadId();
1723 assert(id < (int) cache_info->number_threads);
1724 indexes=GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]);
1729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1733 % G e t A u t h e n t i c I n d e x Q u e u e %
1737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1739 % GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1740 % indexes associated with the last call to QueueAuthenticPixels() or
1741 % GetVirtualPixels(). NULL is returned if the black channel or colormap
1742 % indexes are not available.
1744 % The format of the GetAuthenticIndexQueue() method is:
1746 % IndexPacket *GetAuthenticIndexQueue(const Image *image)
1748 % A description of each parameter follows:
1750 % o image: the image.
1753 MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1758 assert(image != (const Image *) NULL);
1759 assert(image->signature == MagickSignature);
1760 assert(image->cache != (Cache) NULL);
1761 cache_info=(CacheInfo *) image->cache;
1762 assert(cache_info->signature == MagickSignature);
1763 if (cache_info->methods.get_authentic_indexes_from_handler ==
1764 (GetAuthenticIndexesFromHandler) NULL)
1765 return((IndexPacket *) NULL);
1766 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1774 + 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 %
1778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1780 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1781 % disk pixel cache as defined by the geometry parameters. A pointer to the
1782 % pixels is returned if the pixels are transferred, otherwise a NULL is
1785 % The format of the GetAuthenticPixelCacheNexus() method is:
1787 % PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1788 % const ssize_t y,const size_t columns,const size_t rows,
1789 % NexusInfo *nexus_info,ExceptionInfo *exception)
1791 % A description of each parameter follows:
1793 % o image: the image.
1795 % o x,y,columns,rows: These values define the perimeter of a region of
1798 % o nexus_info: the cache nexus to return.
1800 % o exception: return any errors or warnings in this structure.
1804 static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1805 NexusInfo *nexus_info)
1810 if (cache_info->type == PingCache)
1812 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1813 nexus_info->region.x;
1814 if (nexus_info->pixels != (cache_info->pixels+offset))
1815 return(MagickFalse);
1819 MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1820 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1821 NexusInfo *nexus_info,ExceptionInfo *exception)
1830 Transfer pixels from the cache.
1832 assert(image != (Image *) NULL);
1833 assert(image->signature == MagickSignature);
1834 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1835 if (pixels == (PixelPacket *) NULL)
1836 return((PixelPacket *) NULL);
1837 cache_info=(CacheInfo *) image->cache;
1838 assert(cache_info->signature == MagickSignature);
1839 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1841 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1842 return((PixelPacket *) NULL);
1843 if (cache_info->active_index_channel != MagickFalse)
1844 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1845 return((PixelPacket *) NULL);
1850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1854 + 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 %
1858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1860 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1861 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1863 % The format of the GetAuthenticPixelsFromCache() method is:
1865 % PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1867 % A description of each parameter follows:
1869 % o image: the image.
1872 static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1883 cache_info=(CacheInfo *) image->cache;
1884 id=GetOpenMPThreadId();
1885 assert(id < (int) cache_info->number_threads);
1886 pixels=GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]);
1891 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1895 % G e t A u t h e n t i c P i x e l Q u e u e %
1899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1901 % GetAuthenticPixelQueue() returns the authentic pixels associated with the
1902 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
1904 % The format of the GetAuthenticPixelQueue() method is:
1906 % PixelPacket *GetAuthenticPixelQueue(const Image image)
1908 % A description of each parameter follows:
1910 % o image: the image.
1913 MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1918 assert(image != (const Image *) NULL);
1919 assert(image->signature == MagickSignature);
1920 assert(image->cache != (Cache) NULL);
1921 cache_info=(CacheInfo *) image->cache;
1922 assert(cache_info->signature == MagickSignature);
1923 if (cache_info->methods.get_authentic_pixels_from_handler ==
1924 (GetAuthenticPixelsFromHandler) NULL)
1925 return((PixelPacket *) NULL);
1926 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1934 % G e t A u t h e n t i c P i x e l s %
1938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1940 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1941 % region is successfully accessed, a pointer to a PixelPacket array
1942 % representing the region is returned, otherwise NULL is returned.
1944 % The returned pointer may point to a temporary working copy of the pixels
1945 % or it may point to the original pixels in memory. Performance is maximized
1946 % if the selected region is part of one row, or one or more full rows, since
1947 % then there is opportunity to access the pixels in-place (without a copy)
1948 % if the image is in memory, or in a memory-mapped file. The returned pointer
1949 % must *never* be deallocated by the user.
1951 % Pixels accessed via the returned pointer represent a simple array of type
1952 % PixelPacket. If the image type is CMYK or if the storage class is
1953 % PseduoClass, call GetAuthenticIndexQueue() after invoking
1954 % GetAuthenticPixels() to obtain the black color component or colormap indexes
1955 % (of type IndexPacket) corresponding to the region. Once the PixelPacket
1956 % (and/or IndexPacket) array has been updated, the changes must be saved back
1957 % to the underlying image using SyncAuthenticPixels() or they may be lost.
1959 % The format of the GetAuthenticPixels() method is:
1961 % PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1962 % const ssize_t y,const size_t columns,const size_t rows,
1963 % ExceptionInfo *exception)
1965 % A description of each parameter follows:
1967 % o image: the image.
1969 % o x,y,columns,rows: These values define the perimeter of a region of
1972 % o exception: return any errors or warnings in this structure.
1975 MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1976 const ssize_t y,const size_t columns,const size_t rows,
1977 ExceptionInfo *exception)
1985 assert(image != (Image *) NULL);
1986 assert(image->signature == MagickSignature);
1987 assert(image->cache != (Cache) NULL);
1988 cache_info=(CacheInfo *) image->cache;
1989 assert(cache_info->signature == MagickSignature);
1990 if (cache_info->methods.get_authentic_pixels_handler ==
1991 (GetAuthenticPixelsHandler) NULL)
1992 return((PixelPacket *) NULL);
1993 pixels=cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2003 + G e t A u t h e n t i c P i x e l s C a c h e %
2007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2009 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
2010 % as defined by the geometry parameters. A pointer to the pixels is returned
2011 % if the pixels are transferred, otherwise a NULL is returned.
2013 % The format of the GetAuthenticPixelsCache() method is:
2015 % PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2016 % const ssize_t y,const size_t columns,const size_t rows,
2017 % ExceptionInfo *exception)
2019 % A description of each parameter follows:
2021 % o image: the image.
2023 % o x,y,columns,rows: These values define the perimeter of a region of
2026 % o exception: return any errors or warnings in this structure.
2029 static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
2030 const ssize_t y,const size_t columns,const size_t rows,
2031 ExceptionInfo *exception)
2042 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2043 if (cache_info == (Cache) NULL)
2044 return((PixelPacket *) NULL);
2045 id=GetOpenMPThreadId();
2046 assert(id < (int) cache_info->number_threads);
2047 pixels=GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
2048 cache_info->nexus_info[id],exception);
2053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2057 + G e t I m a g e E x t e n t %
2061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2063 % GetImageExtent() returns the extent of the pixels associated with the
2064 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
2066 % The format of the GetImageExtent() method is:
2068 % MagickSizeType GetImageExtent(const Image *image)
2070 % A description of each parameter follows:
2072 % o image: the image.
2075 MagickExport MagickSizeType GetImageExtent(const Image *image)
2086 assert(image != (Image *) NULL);
2087 assert(image->signature == MagickSignature);
2088 if (image->debug != MagickFalse)
2089 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2090 assert(image->cache != (Cache) NULL);
2091 cache_info=(CacheInfo *) image->cache;
2092 assert(cache_info->signature == MagickSignature);
2093 id=GetOpenMPThreadId();
2094 assert(id < (int) cache_info->number_threads);
2095 extent=GetPixelCacheNexusExtent(image->cache,cache_info->nexus_info[id]);
2100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2104 + G e t I m a g e P i x e l C a c h e %
2108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2110 % GetImagePixelCache() ensures that there is only a single reference to the
2111 % pixel cache to be modified, updating the provided cache pointer to point to
2112 % a clone of the original pixel cache if necessary.
2114 % The format of the GetImagePixelCache method is:
2116 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2117 % ExceptionInfo *exception)
2119 % A description of each parameter follows:
2121 % o image: the image.
2123 % o clone: any value other than MagickFalse clones the cache pixels.
2125 % o exception: return any errors or warnings in this structure.
2128 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2134 Does the image match the pixel cache morphology?
2136 cache_info=(CacheInfo *) image->cache;
2137 if ((image->storage_class != cache_info->storage_class) ||
2138 (image->colorspace != cache_info->colorspace) ||
2139 (image->columns != cache_info->columns) ||
2140 (image->rows != cache_info->rows) ||
2141 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2142 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2143 return(MagickFalse);
2147 MagickExport Cache GetImagePixelCache(Image *image,
2148 const MagickBooleanType clone,ExceptionInfo *exception)
2157 static MagickSizeType
2166 LockSemaphoreInfo(image->semaphore);
2167 if (cpu_throttle == 0)
2173 Set CPU throttle in milleseconds.
2175 cpu_throttle=MagickResourceInfinity;
2176 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2177 if (limit == (char *) NULL)
2178 limit=GetPolicyValue("throttle");
2179 if (limit != (char *) NULL)
2181 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2182 limit=DestroyString(limit);
2185 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2186 MagickDelay(cpu_throttle);
2187 if (time_limit == 0)
2190 Set the exire time in seconds.
2192 time_limit=GetMagickResourceLimit(TimeResource);
2193 cache_genesis=time((time_t *) NULL);
2195 if ((time_limit != MagickResourceInfinity) &&
2196 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
2197 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2198 assert(image->cache != (Cache) NULL);
2199 cache_info=(CacheInfo *) image->cache;
2200 destroy=MagickFalse;
2201 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2203 LockSemaphoreInfo(cache_info->semaphore);
2204 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2215 clone_image=(*image);
2216 clone_image.semaphore=AllocateSemaphoreInfo();
2217 clone_image.reference_count=1;
2218 clone_image.cache=ClonePixelCache(cache_info);
2219 clone_info=(CacheInfo *) clone_image.cache;
2220 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
2221 if (status != MagickFalse)
2223 status=OpenPixelCache(&clone_image,IOMode,exception);
2224 if (status != MagickFalse)
2226 if (clone != MagickFalse)
2227 status=ClonePixelCachePixels(clone_info,cache_info,
2229 if (status != MagickFalse)
2232 image->cache=clone_image.cache;
2236 DestroySemaphoreInfo(&clone_image.semaphore);
2238 UnlockSemaphoreInfo(cache_info->semaphore);
2240 if (destroy != MagickFalse)
2241 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2242 if (status != MagickFalse)
2245 Ensure the image matches the pixel cache morphology.
2247 image->taint=MagickTrue;
2248 image->type=UndefinedType;
2249 if (image->colorspace == GRAYColorspace)
2250 image->colorspace=RGBColorspace;
2251 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2252 status=OpenPixelCache(image,IOMode,exception);
2254 UnlockSemaphoreInfo(image->semaphore);
2255 if (status == MagickFalse)
2256 return((Cache) NULL);
2257 return(image->cache);
2261 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2265 % G e t O n e A u t h e n t i c P i x e l %
2269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2271 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2272 % location. The image background color is returned if an error occurs.
2274 % The format of the GetOneAuthenticPixel() method is:
2276 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2277 % const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2279 % A description of each parameter follows:
2281 % o image: the image.
2283 % o x,y: These values define the location of the pixel to return.
2285 % o pixel: return a pixel at the specified (x,y) location.
2287 % o exception: return any errors or warnings in this structure.
2290 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2291 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2296 GetOneAuthenticPixelFromHandler
2297 get_one_authentic_pixel_from_handler;
2302 assert(image != (Image *) NULL);
2303 assert(image->signature == MagickSignature);
2304 assert(image->cache != (Cache) NULL);
2305 cache_info=(CacheInfo *) image->cache;
2306 assert(cache_info->signature == MagickSignature);
2307 *pixel=image->background_color;
2308 get_one_authentic_pixel_from_handler=
2309 cache_info->methods.get_one_authentic_pixel_from_handler;
2310 if (get_one_authentic_pixel_from_handler ==
2311 (GetOneAuthenticPixelFromHandler) NULL)
2312 return(MagickFalse);
2313 status=cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2323 + 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 %
2327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2329 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2330 % location. The image background color is returned if an error occurs.
2332 % The format of the GetOneAuthenticPixelFromCache() method is:
2334 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2335 % const ssize_t x,const ssize_t y,PixelPacket *pixel,
2336 % ExceptionInfo *exception)
2338 % A description of each parameter follows:
2340 % o image: the image.
2342 % o x,y: These values define the location of the pixel to return.
2344 % o pixel: return a pixel at the specified (x,y) location.
2346 % o exception: return any errors or warnings in this structure.
2349 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2350 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2355 *pixel=image->background_color;
2356 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2357 if (pixels == (PixelPacket *) NULL)
2358 return(MagickFalse);
2364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2368 % G e t O n e V i r t u a l M a g i c k P i x e l %
2372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2374 % GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2375 % location. The image background color is returned if an error occurs. If
2376 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2378 % The format of the GetOneVirtualMagickPixel() method is:
2380 % MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2381 % const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2382 % ExceptionInfo exception)
2384 % A description of each parameter follows:
2386 % o image: the image.
2388 % o x,y: these values define the location of the pixel to return.
2390 % o pixel: return a pixel at the specified (x,y) location.
2392 % o exception: return any errors or warnings in this structure.
2395 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2396 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2397 ExceptionInfo *exception)
2402 register const IndexPacket
2405 register const PixelPacket
2408 assert(image != (const Image *) NULL);
2409 assert(image->signature == MagickSignature);
2410 assert(image->cache != (Cache) NULL);
2411 cache_info=(CacheInfo *) image->cache;
2412 assert(cache_info->signature == MagickSignature);
2413 GetMagickPixelPacket(image,pixel);
2414 p=GetVirtualPixelCache(image,GetPixelCacheVirtualMethod(image),x,y,1,1,
2416 if (p == (const PixelPacket *) NULL)
2417 return(MagickFalse);
2418 indexes=GetVirtualIndexQueue(image);
2419 SetMagickPixelPacket(image,p,indexes,pixel);
2424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2428 % G e t O n e V i r t u a l M e t h o d P i x e l %
2432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2434 % GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2435 % location as defined by specified pixel method. The image background color
2436 % is returned if an error occurs. If you plan to modify the pixel, use
2437 % GetOneAuthenticPixel() instead.
2439 % The format of the GetOneVirtualMethodPixel() method is:
2441 % MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2442 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2443 % const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
2445 % A description of each parameter follows:
2447 % o image: the image.
2449 % o virtual_pixel_method: the virtual pixel method.
2451 % o x,y: These values define the location of the pixel to return.
2453 % o pixel: return a pixel at the specified (x,y) location.
2455 % o exception: return any errors or warnings in this structure.
2458 MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2459 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2460 PixelPacket *pixel,ExceptionInfo *exception)
2462 GetOneVirtualPixelFromHandler
2463 get_one_virtual_pixel_from_handler;
2471 assert(image != (const Image *) NULL);
2472 assert(image->signature == MagickSignature);
2473 assert(image->cache != (Cache) NULL);
2474 cache_info=(CacheInfo *) image->cache;
2475 assert(cache_info->signature == MagickSignature);
2476 *pixel=image->background_color;
2477 get_one_virtual_pixel_from_handler=
2478 cache_info->methods.get_one_virtual_pixel_from_handler;
2479 if (get_one_virtual_pixel_from_handler ==
2480 (GetOneVirtualPixelFromHandler) NULL)
2481 return(MagickFalse);
2482 status=get_one_virtual_pixel_from_handler(image,virtual_pixel_method,x,y,
2488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2492 % G e t O n e V i r t u a l P i x e l %
2496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2498 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2499 % (x,y) location. The image background color is returned if an error occurs.
2500 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2502 % The format of the GetOneVirtualPixel() method is:
2504 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2505 % const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
2507 % A description of each parameter follows:
2509 % o image: the image.
2511 % o x,y: These values define the location of the pixel to return.
2513 % o pixel: return a pixel at the specified (x,y) location.
2515 % o exception: return any errors or warnings in this structure.
2518 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2519 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2521 GetOneVirtualPixelFromHandler
2522 get_one_virtual_pixel_from_handler;
2530 assert(image != (const Image *) NULL);
2531 assert(image->signature == MagickSignature);
2532 assert(image->cache != (Cache) NULL);
2533 cache_info=(CacheInfo *) image->cache;
2534 assert(cache_info->signature == MagickSignature);
2535 *pixel=image->background_color;
2536 get_one_virtual_pixel_from_handler=
2537 cache_info->methods.get_one_virtual_pixel_from_handler;
2538 if (get_one_virtual_pixel_from_handler ==
2539 (GetOneVirtualPixelFromHandler) NULL)
2540 return(MagickFalse);
2541 status=get_one_virtual_pixel_from_handler(image,GetPixelCacheVirtualMethod(
2542 image),x,y,pixel,exception);
2547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2551 + 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 %
2555 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2557 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2558 % specified (x,y) location. The image background color is returned if an
2561 % The format of the GetOneVirtualPixelFromCache() method is:
2563 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2564 % const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
2565 % PixelPacket *pixel,ExceptionInfo *exception)
2567 % A description of each parameter follows:
2569 % o image: the image.
2571 % o virtual_pixel_method: the virtual pixel method.
2573 % o x,y: These values define the location of the pixel to return.
2575 % o pixel: return a pixel at the specified (x,y) location.
2577 % o exception: return any errors or warnings in this structure.
2580 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2581 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2582 PixelPacket *pixel,ExceptionInfo *exception)
2587 *pixel=image->background_color;
2588 pixels=GetVirtualPixelCache(image,virtual_pixel_method,x,y,1UL,1UL,exception);
2589 if (pixels == (const PixelPacket *) NULL)
2590 return(MagickFalse);
2596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2600 + G e t P i x e l C a c h e C o l o r s p a c e %
2604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2606 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2608 % The format of the GetPixelCacheColorspace() method is:
2610 % Colorspace GetPixelCacheColorspace(Cache cache)
2612 % A description of each parameter follows:
2614 % o cache: the pixel cache.
2617 MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2622 assert(cache != (Cache) NULL);
2623 cache_info=(CacheInfo *) cache;
2624 assert(cache_info->signature == MagickSignature);
2625 if (cache_info->debug != MagickFalse)
2626 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2627 cache_info->filename);
2628 return(cache_info->colorspace);
2632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2636 + G e t P i x e l C a c h e M e t h o d s %
2640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2642 % GetPixelCacheMethods() initializes the CacheMethods structure.
2644 % The format of the GetPixelCacheMethods() method is:
2646 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2648 % A description of each parameter follows:
2650 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2653 MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2655 assert(cache_methods != (CacheMethods *) NULL);
2656 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2657 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2658 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2659 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2660 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2661 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2662 cache_methods->get_authentic_indexes_from_handler=
2663 GetAuthenticIndexesFromCache;
2664 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2665 cache_methods->get_one_authentic_pixel_from_handler=
2666 GetOneAuthenticPixelFromCache;
2667 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2668 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2669 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2677 + G e t P i x e l C a c h e N e x u s E x t e n t %
2681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2683 % GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2684 % the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2686 % The format of the GetPixelCacheNexusExtent() method is:
2688 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2689 % NexusInfo *nexus_info)
2691 % A description of each parameter follows:
2693 % o nexus_info: the nexus info.
2696 MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2697 NexusInfo *nexus_info)
2705 if (cache == (Cache) NULL)
2707 cache_info=(CacheInfo *) cache;
2708 assert(cache_info->signature == MagickSignature);
2709 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2711 return((MagickSizeType) cache_info->columns*cache_info->rows);
2716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2720 + 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 %
2724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2726 % GetPixelCacheNexusIndexes() returns the indexes associated with the
2727 % specified cache nexus.
2729 % The format of the GetPixelCacheNexusIndexes() method is:
2731 % IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2732 % NexusInfo *nexus_info)
2734 % A description of each parameter follows:
2736 % o cache: the pixel cache.
2738 % o nexus_info: the cache nexus to return the colormap indexes.
2741 MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2742 NexusInfo *nexus_info)
2747 if (cache == (Cache) NULL)
2748 return((IndexPacket *) NULL);
2749 cache_info=(CacheInfo *) cache;
2750 assert(cache_info->signature == MagickSignature);
2751 if (cache_info->storage_class == UndefinedClass)
2752 return((IndexPacket *) NULL);
2753 return(nexus_info->indexes);
2757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2761 + G e t P i x e l C a c h e N e x u s P i x e l s %
2765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2767 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2770 % The format of the GetPixelCacheNexusPixels() method is:
2772 % PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2773 % NexusInfo *nexus_info)
2775 % A description of each parameter follows:
2777 % o cache: the pixel cache.
2779 % o nexus_info: the cache nexus to return the pixels.
2782 MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2783 NexusInfo *nexus_info)
2788 if (cache == (Cache) NULL)
2789 return((PixelPacket *) NULL);
2790 cache_info=(CacheInfo *) cache;
2791 assert(cache_info->signature == MagickSignature);
2792 if (cache_info->storage_class == UndefinedClass)
2793 return((PixelPacket *) NULL);
2794 return(nexus_info->pixels);
2798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2802 + G e t P i x e l C a c h e P i x e l s %
2806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2808 % GetPixelCachePixels() returns the pixels associated with the specified image.
2810 % The format of the GetPixelCachePixels() method is:
2812 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2813 % ExceptionInfo *exception)
2815 % A description of each parameter follows:
2817 % o image: the image.
2819 % o length: the pixel cache length.
2821 % o exception: return any errors or warnings in this structure.
2824 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2825 ExceptionInfo *exception)
2830 assert(image != (const Image *) NULL);
2831 assert(image->signature == MagickSignature);
2832 assert(image->cache != (Cache) NULL);
2833 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
2834 assert(cache_info->signature == MagickSignature);
2836 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2837 return((void *) NULL);
2838 *length=cache_info->length;
2839 return((void *) cache_info->pixels);
2843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847 + 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 %
2851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2853 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2855 % The format of the GetPixelCacheStorageClass() method is:
2857 % ClassType GetPixelCacheStorageClass(Cache cache)
2859 % A description of each parameter follows:
2861 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2863 % o cache: the pixel cache.
2866 MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2871 assert(cache != (Cache) NULL);
2872 cache_info=(CacheInfo *) cache;
2873 assert(cache_info->signature == MagickSignature);
2874 if (cache_info->debug != MagickFalse)
2875 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2876 cache_info->filename);
2877 return(cache_info->storage_class);
2881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2885 + G e t P i x e l C a c h e T i l e S i z e %
2889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891 % GetPixelCacheTileSize() returns the pixel cache tile size.
2893 % The format of the GetPixelCacheTileSize() method is:
2895 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2898 % A description of each parameter follows:
2900 % o image: the image.
2902 % o width: the optimize cache tile width in pixels.
2904 % o height: the optimize cache tile height in pixels.
2907 MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2913 assert(image != (Image *) NULL);
2914 assert(image->signature == MagickSignature);
2915 if (image->debug != MagickFalse)
2916 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2917 assert(image->cache != (Cache) NULL);
2918 cache_info=(CacheInfo *) image->cache;
2919 assert(cache_info->signature == MagickSignature);
2920 *width=2048UL/sizeof(PixelPacket);
2921 if (GetPixelCacheType(image) == DiskCache)
2922 *width=8192UL/sizeof(PixelPacket);
2927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2931 + G e t P i x e l C a c h e T y p e %
2935 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2937 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2939 % The format of the GetPixelCacheType() method is:
2941 % CacheType GetPixelCacheType(const Image *image)
2943 % A description of each parameter follows:
2945 % o image: the image.
2948 MagickExport CacheType GetPixelCacheType(const Image *image)
2953 assert(image != (Image *) NULL);
2954 assert(image->signature == MagickSignature);
2955 assert(image->cache != (Cache) NULL);
2956 cache_info=(CacheInfo *) image->cache;
2957 assert(cache_info->signature == MagickSignature);
2958 return(cache_info->type);
2962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2966 + 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 %
2970 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2972 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2973 % pixel cache. A virtual pixel is any pixel access that is outside the
2974 % boundaries of the image cache.
2976 % The format of the GetPixelCacheVirtualMethod() method is:
2978 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2980 % A description of each parameter follows:
2982 % o image: the image.
2985 MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2990 assert(image != (Image *) NULL);
2991 assert(image->signature == MagickSignature);
2992 assert(image->cache != (Cache) NULL);
2993 cache_info=(CacheInfo *) image->cache;
2994 assert(cache_info->signature == MagickSignature);
2995 return(cache_info->virtual_pixel_method);
2999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3003 + 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 %
3007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3009 % GetVirtualIndexesFromCache() returns the indexes associated with the last
3010 % call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3012 % The format of the GetVirtualIndexesFromCache() method is:
3014 % IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3016 % A description of each parameter follows:
3018 % o image: the image.
3021 static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
3032 cache_info=(CacheInfo *) image->cache;
3033 id=GetOpenMPThreadId();
3034 assert(id < (int) cache_info->number_threads);
3035 indexes=GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]);
3040 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3044 + 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 %
3048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3050 % GetVirtualIndexesFromNexus() returns the indexes associated with the
3051 % specified cache nexus.
3053 % The format of the GetVirtualIndexesFromNexus() method is:
3055 % const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3056 % NexusInfo *nexus_info)
3058 % A description of each parameter follows:
3060 % o cache: the pixel cache.
3062 % o nexus_info: the cache nexus to return the colormap indexes.
3065 MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
3066 NexusInfo *nexus_info)
3071 if (cache == (Cache) NULL)
3072 return((IndexPacket *) NULL);
3073 cache_info=(CacheInfo *) cache;
3074 assert(cache_info->signature == MagickSignature);
3075 if (cache_info->storage_class == UndefinedClass)
3076 return((IndexPacket *) NULL);
3077 return(nexus_info->indexes);
3081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3085 % G e t V i r t u a l I n d e x Q u e u e %
3089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3091 % GetVirtualIndexQueue() returns the virtual black channel or the
3092 % colormap indexes associated with the last call to QueueAuthenticPixels() or
3093 % GetVirtualPixels(). NULL is returned if the black channel or colormap
3094 % indexes are not available.
3096 % The format of the GetVirtualIndexQueue() method is:
3098 % const IndexPacket *GetVirtualIndexQueue(const Image *image)
3100 % A description of each parameter follows:
3102 % o image: the image.
3105 MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3110 assert(image != (const Image *) NULL);
3111 assert(image->signature == MagickSignature);
3112 assert(image->cache != (Cache) NULL);
3113 cache_info=(CacheInfo *) image->cache;
3114 assert(cache_info->signature == MagickSignature);
3115 if (cache_info->methods.get_virtual_indexes_from_handler ==
3116 (GetVirtualIndexesFromHandler) NULL)
3117 return((IndexPacket *) NULL);
3118 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3122 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3126 + 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 %
3130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3132 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3133 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3134 % is returned if the pixels are transferred, otherwise a NULL is returned.
3136 % The format of the GetVirtualPixelsFromNexus() method is:
3138 % PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3139 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3140 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
3141 % ExceptionInfo *exception)
3143 % A description of each parameter follows:
3145 % o image: the image.
3147 % o virtual_pixel_method: the virtual pixel method.
3149 % o x,y,columns,rows: These values define the perimeter of a region of
3152 % o nexus_info: the cache nexus to acquire.
3154 % o exception: return any errors or warnings in this structure.
3161 0, 48, 12, 60, 3, 51, 15, 63,
3162 32, 16, 44, 28, 35, 19, 47, 31,
3163 8, 56, 4, 52, 11, 59, 7, 55,
3164 40, 24, 36, 20, 43, 27, 39, 23,
3165 2, 50, 14, 62, 1, 49, 13, 61,
3166 34, 18, 46, 30, 33, 17, 45, 29,
3167 10, 58, 6, 54, 9, 57, 5, 53,
3168 42, 26, 38, 22, 41, 25, 37, 21
3171 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3176 index=x+DitherMatrix[x & 0x07]-32L;
3179 if (index >= (ssize_t) columns)
3180 return((ssize_t) columns-1L);
3184 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3189 index=y+DitherMatrix[y & 0x07]-32L;
3192 if (index >= (ssize_t) rows)
3193 return((ssize_t) rows-1L);
3197 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3201 if (x >= (ssize_t) columns)
3202 return((ssize_t) (columns-1));
3206 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3210 if (y >= (ssize_t) rows)
3211 return((ssize_t) (rows-1));
3215 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3217 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3220 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3222 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3226 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3227 returns not only the quotient (tile the offset falls in) but also the positive
3228 remainer within that tile such that 0 <= remainder < extent. This method is
3229 essentially a ldiv() using a floored modulo division rather than the normal
3230 default truncated modulo division.
3232 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3233 const size_t extent)
3238 modulo.quotient=offset/(ssize_t) extent;
3241 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3245 MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3246 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3247 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3248 ExceptionInfo *exception)
3273 register const IndexPacket
3274 *restrict virtual_indexes;
3276 register const PixelPacket
3279 register IndexPacket
3282 register PixelPacket
3292 cache_info=(CacheInfo *) image->cache;
3293 if (cache_info->type == UndefinedCache)
3294 return((const PixelPacket *) NULL);
3297 region.width=columns;
3299 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3300 if (pixels == (PixelPacket *) NULL)
3301 return((const PixelPacket *) NULL);
3302 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3303 nexus_info->region.x;
3304 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3305 nexus_info->region.width-1L;
3306 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3307 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3308 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3309 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3315 Pixel request is inside cache extents.
3317 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3319 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3320 if (status == MagickFalse)
3321 return((const PixelPacket *) NULL);
3322 if ((cache_info->storage_class == PseudoClass) ||
3323 (cache_info->colorspace == CMYKColorspace))
3325 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3326 if (status == MagickFalse)
3327 return((const PixelPacket *) NULL);
3332 Pixel request is outside cache extents.
3335 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3336 virtual_nexus=AcquirePixelCacheNexus(1);
3337 if (virtual_nexus == (NexusInfo **) NULL)
3339 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3340 "UnableToGetCacheNexus","`%s'",image->filename);
3341 return((const PixelPacket *) NULL);
3343 switch (virtual_pixel_method)
3345 case BlackVirtualPixelMethod:
3347 SetRedPixelComponent(&virtual_pixel,0);
3348 SetGreenPixelComponent(&virtual_pixel,0);
3349 SetBluePixelComponent(&virtual_pixel,0);
3350 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3353 case GrayVirtualPixelMethod:
3355 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3356 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3357 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3358 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3361 case TransparentVirtualPixelMethod:
3363 SetRedPixelComponent(&virtual_pixel,0);
3364 SetGreenPixelComponent(&virtual_pixel,0);
3365 SetBluePixelComponent(&virtual_pixel,0);
3366 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
3369 case MaskVirtualPixelMethod:
3370 case WhiteVirtualPixelMethod:
3372 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3373 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3374 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3375 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3380 virtual_pixel=image->background_color;
3385 for (v=0; v < (ssize_t) rows; v++)
3387 for (u=0; u < (ssize_t) columns; u+=length)
3389 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3390 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3391 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3399 Transfer a single pixel.
3401 length=(MagickSizeType) 1;
3402 switch (virtual_pixel_method)
3404 case BackgroundVirtualPixelMethod:
3405 case ConstantVirtualPixelMethod:
3406 case BlackVirtualPixelMethod:
3407 case GrayVirtualPixelMethod:
3408 case TransparentVirtualPixelMethod:
3409 case MaskVirtualPixelMethod:
3410 case WhiteVirtualPixelMethod:
3413 virtual_indexes=(&virtual_index);
3416 case EdgeVirtualPixelMethod:
3419 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3420 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3421 1UL,1UL,virtual_nexus[0],exception);
3422 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3426 case RandomVirtualPixelMethod:
3428 if (cache_info->random_info == (RandomInfo *) NULL)
3429 cache_info->random_info=AcquireRandomInfo();
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3431 RandomX(cache_info->random_info,cache_info->columns),
3432 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3433 virtual_nexus[0],exception);
3434 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3438 case DitherVirtualPixelMethod:
3440 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3441 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3442 1UL,1UL,virtual_nexus[0],exception);
3443 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3447 case TileVirtualPixelMethod:
3449 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3450 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3451 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3452 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3454 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3458 case MirrorVirtualPixelMethod:
3460 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3461 if ((x_modulo.quotient & 0x01) == 1L)
3462 x_modulo.remainder=(ssize_t) cache_info->columns-
3463 x_modulo.remainder-1L;
3464 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3465 if ((y_modulo.quotient & 0x01) == 1L)
3466 y_modulo.remainder=(ssize_t) cache_info->rows-
3467 y_modulo.remainder-1L;
3468 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3469 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3471 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3475 case CheckerTileVirtualPixelMethod:
3477 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3478 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3479 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3482 virtual_indexes=(&virtual_index);
3485 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3486 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3488 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3492 case HorizontalTileVirtualPixelMethod:
3494 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3497 virtual_indexes=(&virtual_index);
3500 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3501 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3502 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3503 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3505 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3509 case VerticalTileVirtualPixelMethod:
3511 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3514 virtual_indexes=(&virtual_index);
3517 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3518 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3519 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3520 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3522 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3526 case HorizontalTileEdgeVirtualPixelMethod:
3528 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3529 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3530 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3531 virtual_nexus[0],exception);
3532 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3536 case VerticalTileEdgeVirtualPixelMethod:
3538 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3539 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3540 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3541 virtual_nexus[0],exception);
3542 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3547 if (p == (const PixelPacket *) NULL)
3550 if ((indexes != (IndexPacket *) NULL) &&
3551 (virtual_indexes != (const IndexPacket *) NULL))
3552 *indexes++=(*virtual_indexes);
3556 Transfer a run of pixels.
3558 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3559 (size_t) length,1UL,virtual_nexus[0],exception);
3560 if (p == (const PixelPacket *) NULL)
3562 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
3563 (void) CopyMagickMemory(q,p,(size_t) length*sizeof(*p));
3565 if ((indexes != (IndexPacket *) NULL) &&
3566 (virtual_indexes != (const IndexPacket *) NULL))
3568 (void) CopyMagickMemory(indexes,virtual_indexes,(size_t) length*
3569 sizeof(*virtual_indexes));
3574 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3583 + G e t V i r t u a l P i x e l C a c h e %
3587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3589 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3590 % cache as defined by the geometry parameters. A pointer to the pixels
3591 % is returned if the pixels are transferred, otherwise a NULL is returned.
3593 % The format of the GetVirtualPixelCache() method is:
3595 % const PixelPacket *GetVirtualPixelCache(const Image *image,
3596 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3597 % const ssize_t y,const size_t columns,const size_t rows,
3598 % ExceptionInfo *exception)
3600 % A description of each parameter follows:
3602 % o image: the image.
3604 % o virtual_pixel_method: the virtual pixel method.
3606 % o x,y,columns,rows: These values define the perimeter of a region of
3609 % o exception: return any errors or warnings in this structure.
3612 static const PixelPacket *GetVirtualPixelCache(const Image *image,
3613 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3614 const size_t columns,const size_t rows,ExceptionInfo *exception)
3625 cache_info=(CacheInfo *) image->cache;
3626 id=GetOpenMPThreadId();
3627 assert(id < (int) cache_info->number_threads);
3628 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3629 cache_info->nexus_info[id],exception);
3634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3638 % G e t V i r t u a l P i x e l Q u e u e %
3642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3644 % GetVirtualPixelQueue() returns the virtual pixels associated with the
3645 % last call to QueueAuthenticPixels() or GetVirtualPixels().
3647 % The format of the GetVirtualPixelQueue() method is:
3649 % const PixelPacket *GetVirtualPixelQueue(const Image image)
3651 % A description of each parameter follows:
3653 % o image: the image.
3656 MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3661 assert(image != (const Image *) NULL);
3662 assert(image->signature == MagickSignature);
3663 assert(image->cache != (Cache) NULL);
3664 cache_info=(CacheInfo *) image->cache;
3665 assert(cache_info->signature == MagickSignature);
3666 if (cache_info->methods.get_virtual_pixels_handler ==
3667 (GetVirtualPixelsHandler) NULL)
3668 return((PixelPacket *) NULL);
3669 return(cache_info->methods.get_virtual_pixels_handler(image));
3673 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3677 % G e t V i r t u a l P i x e l s %
3681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3683 % GetVirtualPixels() returns an immutable pixel region. If the
3684 % region is successfully accessed, a pointer to it is returned, otherwise
3685 % NULL is returned. The returned pointer may point to a temporary working
3686 % copy of the pixels or it may point to the original pixels in memory.
3687 % Performance is maximized if the selected region is part of one row, or one
3688 % or more full rows, since there is opportunity to access the pixels in-place
3689 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3690 % returned pointer must *never* be deallocated by the user.
3692 % Pixels accessed via the returned pointer represent a simple array of type
3693 % PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3694 % call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3695 % the black color component or to obtain the colormap indexes (of type
3696 % IndexPacket) corresponding to the region.
3698 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3700 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3701 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3702 % GetCacheViewAuthenticPixels() instead.
3704 % The format of the GetVirtualPixels() method is:
3706 % const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3707 % const ssize_t y,const size_t columns,const size_t rows,
3708 % ExceptionInfo *exception)
3710 % A description of each parameter follows:
3712 % o image: the image.
3714 % o x,y,columns,rows: These values define the perimeter of a region of
3717 % o exception: return any errors or warnings in this structure.
3720 MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3721 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3722 ExceptionInfo *exception)
3730 assert(image != (const Image *) NULL);
3731 assert(image->signature == MagickSignature);
3732 assert(image->cache != (Cache) NULL);
3733 cache_info=(CacheInfo *) image->cache;
3734 assert(cache_info->signature == MagickSignature);
3735 if (cache_info->methods.get_virtual_pixel_handler ==
3736 (GetVirtualPixelHandler) NULL)
3737 return((const PixelPacket *) NULL);
3738 pixels=cache_info->methods.get_virtual_pixel_handler(image,
3739 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception);
3744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3748 + 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 %
3752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3754 % GetVirtualPixelsCache() returns the pixels associated with the last call
3755 % to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3757 % The format of the GetVirtualPixelsCache() method is:
3759 % PixelPacket *GetVirtualPixelsCache(const Image *image)
3761 % A description of each parameter follows:
3763 % o image: the image.
3766 static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3777 cache_info=(CacheInfo *) image->cache;
3778 id=GetOpenMPThreadId();
3779 assert(id < (int) cache_info->number_threads);
3780 pixels=GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]);
3785 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3789 + G e t V i r t u a l P i x e l s N e x u s %
3793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3795 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3798 % The format of the GetVirtualPixelsNexus() method is:
3800 % const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3801 % NexusInfo *nexus_info)
3803 % A description of each parameter follows:
3805 % o cache: the pixel cache.
3807 % o nexus_info: the cache nexus to return the colormap pixels.
3810 MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3811 NexusInfo *nexus_info)
3816 if (cache == (Cache) NULL)
3817 return((PixelPacket *) NULL);
3818 cache_info=(CacheInfo *) cache;
3819 assert(cache_info->signature == MagickSignature);
3820 if (cache_info->storage_class == UndefinedClass)
3821 return((PixelPacket *) NULL);
3822 return((const PixelPacket *) nexus_info->pixels);
3826 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3830 + M a s k P i x e l C a c h e N e x u s %
3834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3836 % MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3837 % The method returns MagickTrue if the pixel region is masked, otherwise
3840 % The format of the MaskPixelCacheNexus() method is:
3842 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3843 % NexusInfo *nexus_info,ExceptionInfo *exception)
3845 % A description of each parameter follows:
3847 % o image: the image.
3849 % o nexus_info: the cache nexus to clip.
3851 % o exception: return any errors or warnings in this structure.
3855 static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3856 const MagickRealType alpha,const MagickPixelPacket *q,
3857 const MagickRealType beta,MagickPixelPacket *composite)
3862 if (alpha == TransparentOpacity)
3867 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3868 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3869 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3870 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3871 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3872 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3873 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3876 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3877 ExceptionInfo *exception)
3893 register const PixelPacket
3896 register IndexPacket
3897 *restrict nexus_indexes,
3900 register PixelPacket
3910 if (image->debug != MagickFalse)
3911 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3912 if (image->mask == (Image *) NULL)
3913 return(MagickFalse);
3914 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
3915 if (cache_info == (Cache) NULL)
3916 return(MagickFalse);
3917 image_nexus=AcquirePixelCacheNexus(1);
3918 clip_nexus=AcquirePixelCacheNexus(1);
3919 if ((image_nexus == (NexusInfo **) NULL) ||
3920 (clip_nexus == (NexusInfo **) NULL))
3921 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3922 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3923 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3924 image_nexus[0],exception);
3925 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3926 q=nexus_info->pixels;
3927 nexus_indexes=nexus_info->indexes;
3928 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3929 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3930 nexus_info->region.height,clip_nexus[0],&image->exception);
3931 GetMagickPixelPacket(image,&alpha);
3932 GetMagickPixelPacket(image,&beta);
3933 number_pixels=(MagickSizeType) nexus_info->region.width*
3934 nexus_info->region.height;
3935 for (i=0; i < (ssize_t) number_pixels; i++)
3937 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3939 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3940 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3941 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3942 &alpha,alpha.opacity,&beta);
3943 q->red=ClampToQuantum(beta.red);
3944 q->green=ClampToQuantum(beta.green);
3945 q->blue=ClampToQuantum(beta.blue);
3946 q->opacity=ClampToQuantum(beta.opacity);
3947 if (cache_info->active_index_channel != MagickFalse)
3948 nexus_indexes[i]=indexes[i];
3953 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3954 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3955 if (i < (ssize_t) number_pixels)
3956 return(MagickFalse);
3961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3965 + O p e n P i x e l C a c h e %
3969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3971 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3972 % dimensions, allocating space for the image pixels and optionally the
3973 % colormap indexes, and memory mapping the cache if it is disk based. The
3974 % cache nexus array is initialized as well.
3976 % The format of the OpenPixelCache() method is:
3978 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3979 % ExceptionInfo *exception)
3981 % A description of each parameter follows:
3983 % o image: the image.
3985 % o mode: ReadMode, WriteMode, or IOMode.
3987 % o exception: return any errors or warnings in this structure.
3991 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3993 cache_info->mapped=MagickFalse;
3994 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3995 cache_info->length);
3996 if (cache_info->pixels == (PixelPacket *) NULL)
3998 cache_info->mapped=MagickTrue;
3999 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4000 cache_info->length);
4004 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
4014 cache_info=(CacheInfo *) image->cache;
4015 if (image->debug != MagickFalse)
4018 format[MaxTextExtent],
4019 message[MaxTextExtent];
4021 (void) FormatMagickSize(length,MagickFalse,format);
4022 (void) FormatMagickString(message,MaxTextExtent,
4023 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
4024 cache_info->cache_filename,cache_info->file,format);
4025 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4027 if (length != (MagickSizeType) ((MagickOffsetType) length))
4028 return(MagickFalse);
4029 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
4031 return(MagickFalse);
4032 if ((MagickSizeType) extent >= length)
4034 offset=(MagickOffsetType) length-1;
4035 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
4036 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
4039 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
4040 ExceptionInfo *exception)
4043 format[MaxTextExtent],
4044 message[MaxTextExtent];
4061 if (image->debug != MagickFalse)
4062 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4063 if ((image->columns == 0) || (image->rows == 0))
4064 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
4065 cache_info=(CacheInfo *) image->cache;
4066 source_info=(*cache_info);
4067 source_info.file=(-1);
4068 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4069 image->filename,(double) GetImageIndexInList(image));
4070 cache_info->mode=mode;
4071 cache_info->rows=image->rows;
4072 cache_info->columns=image->columns;
4073 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4074 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
4075 if (image->ping != MagickFalse)
4077 cache_info->storage_class=image->storage_class;
4078 cache_info->colorspace=image->colorspace;
4079 cache_info->type=PingCache;
4080 cache_info->pixels=(PixelPacket *) NULL;
4081 cache_info->indexes=(IndexPacket *) NULL;
4082 cache_info->length=0;
4085 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4086 packet_size=sizeof(PixelPacket);
4087 if (cache_info->active_index_channel != MagickFalse)
4088 packet_size+=sizeof(IndexPacket);
4089 length=number_pixels*packet_size;
4090 columns=(size_t) (length/cache_info->rows/packet_size);
4091 if (cache_info->columns != columns)
4092 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4094 cache_info->length=length;
4095 status=AcquireMagickResource(AreaResource,cache_info->length);
4096 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4097 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4099 status=AcquireMagickResource(MemoryResource,cache_info->length);
4100 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4101 (cache_info->type == MemoryCache))
4103 AllocatePixelCachePixels(cache_info);
4104 if (cache_info->pixels == (PixelPacket *) NULL)
4105 cache_info->pixels=source_info.pixels;
4109 Create memory pixel cache.
4111 if (image->debug != MagickFalse)
4113 (void) FormatMagickSize(cache_info->length,MagickTrue,
4115 (void) FormatMagickString(message,MaxTextExtent,
4116 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
4117 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4118 (double) cache_info->columns,(double) cache_info->rows,
4120 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4123 cache_info->storage_class=image->storage_class;
4124 cache_info->colorspace=image->colorspace;
4125 cache_info->type=MemoryCache;
4126 cache_info->indexes=(IndexPacket *) NULL;
4127 if (cache_info->active_index_channel != MagickFalse)
4128 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4130 if (source_info.storage_class != UndefinedClass)
4132 status|=ClonePixelCachePixels(cache_info,&source_info,
4134 RelinquishPixelCachePixels(&source_info);
4139 RelinquishMagickResource(MemoryResource,cache_info->length);
4142 Create pixel cache on disk.
4144 status=AcquireMagickResource(DiskResource,cache_info->length);
4145 if (status == MagickFalse)
4147 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4148 "CacheResourcesExhausted","`%s'",image->filename);
4149 return(MagickFalse);
4151 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4153 RelinquishMagickResource(DiskResource,cache_info->length);
4154 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4156 return(MagickFalse);
4158 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4159 cache_info->length);
4160 if (status == MagickFalse)
4162 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4164 return(MagickFalse);
4166 cache_info->storage_class=image->storage_class;
4167 cache_info->colorspace=image->colorspace;
4168 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4169 status=AcquireMagickResource(AreaResource,cache_info->length);
4170 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4171 cache_info->type=DiskCache;
4174 status=AcquireMagickResource(MapResource,cache_info->length);
4175 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4176 (cache_info->type != MemoryCache))
4177 cache_info->type=DiskCache;
4180 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4181 cache_info->offset,(size_t) cache_info->length);
4182 if (cache_info->pixels == (PixelPacket *) NULL)
4184 cache_info->pixels=source_info.pixels;
4185 cache_info->type=DiskCache;
4190 Create file-backed memory-mapped pixel cache.
4192 (void) ClosePixelCacheOnDisk(cache_info);
4193 cache_info->type=MapCache;
4194 cache_info->mapped=MagickTrue;
4195 cache_info->indexes=(IndexPacket *) NULL;
4196 if (cache_info->active_index_channel != MagickFalse)
4197 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4199 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4201 status=ClonePixelCachePixels(cache_info,&source_info,
4203 RelinquishPixelCachePixels(&source_info);
4205 if (image->debug != MagickFalse)
4207 (void) FormatMagickSize(cache_info->length,MagickTrue,
4209 (void) FormatMagickString(message,MaxTextExtent,
4210 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
4211 cache_info->filename,cache_info->cache_filename,
4212 cache_info->file,(double) cache_info->columns,(double)
4213 cache_info->rows,format);
4214 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4220 RelinquishMagickResource(MapResource,cache_info->length);
4222 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4224 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4225 RelinquishPixelCachePixels(&source_info);
4227 if (image->debug != MagickFalse)
4229 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4230 (void) FormatMagickString(message,MaxTextExtent,
4231 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4232 cache_info->cache_filename,cache_info->file,(double)
4233 cache_info->columns,(double) cache_info->rows,format);
4234 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4244 + P e r s i s t P i x e l C a c h e %
4248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4250 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4251 % persistent pixel cache is one that resides on disk and is not destroyed
4252 % when the program exits.
4254 % The format of the PersistPixelCache() method is:
4256 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4257 % const MagickBooleanType attach,MagickOffsetType *offset,
4258 % ExceptionInfo *exception)
4260 % A description of each parameter follows:
4262 % o image: the image.
4264 % o filename: the persistent pixel cache filename.
4266 % o attach: A value other than zero initializes the persistent pixel
4269 % o initialize: A value other than zero initializes the persistent pixel
4272 % o offset: the offset in the persistent cache to store pixels.
4274 % o exception: return any errors or warnings in this structure.
4277 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4278 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4279 ExceptionInfo *exception)
4294 assert(image != (Image *) NULL);
4295 assert(image->signature == MagickSignature);
4296 if (image->debug != MagickFalse)
4297 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4298 assert(image->cache != (void *) NULL);
4299 assert(filename != (const char *) NULL);
4300 assert(offset != (MagickOffsetType *) NULL);
4301 page_size=GetMagickPageSize();
4302 cache_info=(CacheInfo *) image->cache;
4303 assert(cache_info->signature == MagickSignature);
4304 if (attach != MagickFalse)
4307 Attach existing persistent pixel cache.
4309 if (image->debug != MagickFalse)
4310 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4311 "attach persistent cache");
4312 (void) CopyMagickString(cache_info->cache_filename,filename,
4314 cache_info->type=DiskCache;
4315 cache_info->offset=(*offset);
4316 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4317 return(MagickFalse);
4318 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4321 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4322 (cache_info->reference_count == 1))
4324 LockSemaphoreInfo(cache_info->semaphore);
4325 if ((cache_info->mode != ReadMode) &&
4326 (cache_info->type != MemoryCache) &&
4327 (cache_info->reference_count == 1))
4333 Usurp existing persistent pixel cache.
4335 status=rename(cache_info->cache_filename,filename);
4338 (void) CopyMagickString(cache_info->cache_filename,filename,
4340 *offset+=cache_info->length+page_size-(cache_info->length %
4342 UnlockSemaphoreInfo(cache_info->semaphore);
4343 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4344 if (image->debug != MagickFalse)
4345 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4346 "Usurp resident persistent cache");
4350 UnlockSemaphoreInfo(cache_info->semaphore);
4353 Clone persistent pixel cache.
4355 clone_image=(*image);
4356 clone_info=(CacheInfo *) clone_image.cache;
4357 image->cache=ClonePixelCache(cache_info);
4358 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4359 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4360 cache_info->type=DiskCache;
4361 cache_info->offset=(*offset);
4362 cache_info=(CacheInfo *) image->cache;
4363 status=ClonePixelCacheNexus(cache_info,clone_info,exception);
4364 if (status != MagickFalse)
4366 status=OpenPixelCache(image,IOMode,exception);
4367 if (status != MagickFalse)
4368 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4370 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4371 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4380 + Q u e u e A u t h e n t i c N e x u s %
4384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4386 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4387 % by the region rectangle and returns a pointer to the region. This region is
4388 % subsequently transferred from the pixel cache with
4389 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4390 % pixels are transferred, otherwise a NULL is returned.
4392 % The format of the QueueAuthenticNexus() method is:
4394 % PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4395 % const ssize_t y,const size_t columns,const size_t rows,
4396 % NexusInfo *nexus_info,ExceptionInfo *exception)
4398 % A description of each parameter follows:
4400 % o image: the image.
4402 % o x,y,columns,rows: These values define the perimeter of a region of
4405 % o nexus_info: the cache nexus to set.
4407 % o exception: return any errors or warnings in this structure.
4410 MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4411 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4412 ExceptionInfo *exception)
4427 Validate pixel cache geometry.
4429 cache_info=(CacheInfo *) image->cache;
4430 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4432 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4433 "NoPixelsDefinedInCache","`%s'",image->filename);
4434 return((PixelPacket *) NULL);
4436 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4437 (y >= (ssize_t) cache_info->rows))
4439 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4440 "PixelsAreNotAuthentic","`%s'",image->filename);
4441 return((PixelPacket *) NULL);
4443 offset=(MagickOffsetType) y*cache_info->columns+x;
4445 return((PixelPacket *) NULL);
4446 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4447 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4448 if ((MagickSizeType) offset >= number_pixels)
4449 return((PixelPacket *) NULL);
4455 region.width=columns;
4457 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4465 + 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 %
4469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4471 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4472 % defined by the region rectangle and returns a pointer to the region. This
4473 % region is subsequently transferred from the pixel cache with
4474 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4475 % pixels are transferred, otherwise a NULL is returned.
4477 % The format of the QueueAuthenticPixelsCache() method is:
4479 % PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4480 % const ssize_t y,const size_t columns,const size_t rows,
4481 % ExceptionInfo *exception)
4483 % A description of each parameter follows:
4485 % o image: the image.
4487 % o x,y,columns,rows: These values define the perimeter of a region of
4490 % o exception: return any errors or warnings in this structure.
4493 static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4494 const ssize_t y,const size_t columns,const size_t rows,
4495 ExceptionInfo *exception)
4506 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickFalse,exception);
4507 if (cache_info == (Cache) NULL)
4508 return((PixelPacket *) NULL);
4509 id=GetOpenMPThreadId();
4510 assert(id < (int) cache_info->number_threads);
4511 pixels=QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4517 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4521 % Q u e u e A u t h e n t i c P i x e l s %
4525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4527 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4528 % successfully intialized a pointer to a PixelPacket array representing the
4529 % region is returned, otherwise NULL is returned. The returned pointer may
4530 % point to a temporary working buffer for the pixels or it may point to the
4531 % final location of the pixels in memory.
4533 % Write-only access means that any existing pixel values corresponding to
4534 % the region are ignored. This is useful if the initial image is being
4535 % created from scratch, or if the existing pixel values are to be
4536 % completely replaced without need to refer to their pre-existing values.
4537 % The application is free to read and write the pixel buffer returned by
4538 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4539 % initialize the pixel array values. Initializing pixel array values is the
4540 % application's responsibility.
4542 % Performance is maximized if the selected region is part of one row, or
4543 % one or more full rows, since then there is opportunity to access the
4544 % pixels in-place (without a copy) if the image is in memory, or in a
4545 % memory-mapped file. The returned pointer must *never* be deallocated
4548 % Pixels accessed via the returned pointer represent a simple array of type
4549 % PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4550 % call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4551 % the black color component or the colormap indexes (of type IndexPacket)
4552 % corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4553 % array has been updated, the changes must be saved back to the underlying
4554 % image using SyncAuthenticPixels() or they may be lost.
4556 % The format of the QueueAuthenticPixels() method is:
4558 % PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4559 % const ssize_t y,const size_t columns,const size_t rows,
4560 % ExceptionInfo *exception)
4562 % A description of each parameter follows:
4564 % o image: the image.
4566 % o x,y,columns,rows: These values define the perimeter of a region of
4569 % o exception: return any errors or warnings in this structure.
4572 MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4573 const ssize_t y,const size_t columns,const size_t rows,
4574 ExceptionInfo *exception)
4582 assert(image != (Image *) NULL);
4583 assert(image->signature == MagickSignature);
4584 assert(image->cache != (Cache) NULL);
4585 cache_info=(CacheInfo *) image->cache;
4586 assert(cache_info->signature == MagickSignature);
4587 if (cache_info->methods.queue_authentic_pixels_handler ==
4588 (QueueAuthenticPixelsHandler) NULL)
4589 return((PixelPacket *) NULL);
4590 pixels=cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4600 + R e a d P i x e l C a c h e I n d e x e s %
4604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4606 % ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4609 % The format of the ReadPixelCacheIndexes() method is:
4611 % MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4612 % NexusInfo *nexus_info,ExceptionInfo *exception)
4614 % A description of each parameter follows:
4616 % o cache_info: the pixel cache.
4618 % o nexus_info: the cache nexus to read the colormap indexes.
4620 % o exception: return any errors or warnings in this structure.
4623 static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4624 NexusInfo *nexus_info,ExceptionInfo *exception)
4634 register IndexPacket
4643 if (cache_info->active_index_channel == MagickFalse)
4644 return(MagickFalse);
4645 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4647 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4648 nexus_info->region.x;
4649 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4650 rows=nexus_info->region.height;
4651 number_pixels=length*rows;
4652 q=nexus_info->indexes;
4653 switch (cache_info->type)
4658 register IndexPacket
4662 Read indexes from memory.
4664 if ((cache_info->columns == nexus_info->region.width) &&
4665 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4667 length=number_pixels;
4670 p=cache_info->indexes+offset;
4671 for (y=0; y < (ssize_t) rows; y++)
4673 (void) CopyMagickMemory(q,p,(size_t) length);
4674 p+=cache_info->columns;
4675 q+=nexus_info->region.width;
4682 Read indexes from disk.
4684 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4686 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4687 cache_info->cache_filename);
4688 return(MagickFalse);
4690 if ((cache_info->columns == nexus_info->region.width) &&
4691 (number_pixels < MagickMaxBufferExtent))
4693 length=number_pixels;
4696 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4697 for (y=0; y < (ssize_t) rows; y++)
4699 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4700 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4701 if ((MagickSizeType) count < length)
4703 offset+=cache_info->columns;
4704 q+=nexus_info->region.width;
4706 if (y < (ssize_t) rows)
4708 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4709 cache_info->cache_filename);
4710 return(MagickFalse);
4717 if ((cache_info->debug != MagickFalse) &&
4718 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4719 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4720 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4721 nexus_info->region.width,(double) nexus_info->region.height,(double)
4722 nexus_info->region.x,(double) nexus_info->region.y);
4727 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4731 + R e a d P i x e l C a c h e P i x e l s %
4735 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4737 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4740 % The format of the ReadPixelCachePixels() method is:
4742 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4743 % NexusInfo *nexus_info,ExceptionInfo *exception)
4745 % A description of each parameter follows:
4747 % o cache_info: the pixel cache.
4749 % o nexus_info: the cache nexus to read the pixels.
4751 % o exception: return any errors or warnings in this structure.
4754 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4755 NexusInfo *nexus_info,ExceptionInfo *exception)
4765 register PixelPacket
4774 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4776 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4777 nexus_info->region.x;
4778 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4779 rows=nexus_info->region.height;
4780 number_pixels=length*rows;
4781 q=nexus_info->pixels;
4782 switch (cache_info->type)
4787 register PixelPacket
4791 Read pixels from memory.
4793 if ((cache_info->columns == nexus_info->region.width) &&
4794 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4796 length=number_pixels;
4799 p=cache_info->pixels+offset;
4800 for (y=0; y < (ssize_t) rows; y++)
4802 (void) CopyMagickMemory(q,p,(size_t) length);
4803 p+=cache_info->columns;
4804 q+=nexus_info->region.width;
4811 Read pixels from disk.
4813 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4815 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4816 cache_info->cache_filename);
4817 return(MagickFalse);
4819 if ((cache_info->columns == nexus_info->region.width) &&
4820 (number_pixels < MagickMaxBufferExtent))
4822 length=number_pixels;
4825 for (y=0; y < (ssize_t) rows; y++)
4827 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4828 sizeof(*q),length,(unsigned char *) q);
4829 if ((MagickSizeType) count < length)
4831 offset+=cache_info->columns;
4832 q+=nexus_info->region.width;
4834 if (y < (ssize_t) rows)
4836 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4837 cache_info->cache_filename);
4838 return(MagickFalse);
4845 if ((cache_info->debug != MagickFalse) &&
4846 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4847 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4848 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4849 nexus_info->region.width,(double) nexus_info->region.height,(double)
4850 nexus_info->region.x,(double) nexus_info->region.y);
4855 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4859 + R e f e r e n c e P i x e l C a c h e %
4863 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4865 % ReferencePixelCache() increments the reference count associated with the
4866 % pixel cache returning a pointer to the cache.
4868 % The format of the ReferencePixelCache method is:
4870 % Cache ReferencePixelCache(Cache cache_info)
4872 % A description of each parameter follows:
4874 % o cache_info: the pixel cache.
4877 MagickExport Cache ReferencePixelCache(Cache cache)
4882 assert(cache != (Cache *) NULL);
4883 cache_info=(CacheInfo *) cache;
4884 assert(cache_info->signature == MagickSignature);
4885 LockSemaphoreInfo(cache_info->semaphore);
4886 cache_info->reference_count++;
4887 UnlockSemaphoreInfo(cache_info->semaphore);
4892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4896 + S e t P i x e l C a c h e M e t h o d s %
4900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4902 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4904 % The format of the SetPixelCacheMethods() method is:
4906 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4908 % A description of each parameter follows:
4910 % o cache: the pixel cache.
4912 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4915 MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4920 GetOneAuthenticPixelFromHandler
4921 get_one_authentic_pixel_from_handler;
4923 GetOneVirtualPixelFromHandler
4924 get_one_virtual_pixel_from_handler;
4927 Set cache pixel methods.
4929 assert(cache != (Cache) NULL);
4930 assert(cache_methods != (CacheMethods *) NULL);
4931 cache_info=(CacheInfo *) cache;
4932 assert(cache_info->signature == MagickSignature);
4933 if (cache_info->debug != MagickFalse)
4934 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4935 cache_info->filename);
4936 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4937 cache_info->methods.get_virtual_pixel_handler=
4938 cache_methods->get_virtual_pixel_handler;
4939 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4940 cache_info->methods.destroy_pixel_handler=
4941 cache_methods->destroy_pixel_handler;
4942 if (cache_methods->get_virtual_indexes_from_handler !=
4943 (GetVirtualIndexesFromHandler) NULL)
4944 cache_info->methods.get_virtual_indexes_from_handler=
4945 cache_methods->get_virtual_indexes_from_handler;
4946 if (cache_methods->get_authentic_pixels_handler !=
4947 (GetAuthenticPixelsHandler) NULL)
4948 cache_info->methods.get_authentic_pixels_handler=
4949 cache_methods->get_authentic_pixels_handler;
4950 if (cache_methods->queue_authentic_pixels_handler !=
4951 (QueueAuthenticPixelsHandler) NULL)
4952 cache_info->methods.queue_authentic_pixels_handler=
4953 cache_methods->queue_authentic_pixels_handler;
4954 if (cache_methods->sync_authentic_pixels_handler !=
4955 (SyncAuthenticPixelsHandler) NULL)
4956 cache_info->methods.sync_authentic_pixels_handler=
4957 cache_methods->sync_authentic_pixels_handler;
4958 if (cache_methods->get_authentic_pixels_from_handler !=
4959 (GetAuthenticPixelsFromHandler) NULL)
4960 cache_info->methods.get_authentic_pixels_from_handler=
4961 cache_methods->get_authentic_pixels_from_handler;
4962 if (cache_methods->get_authentic_indexes_from_handler !=
4963 (GetAuthenticIndexesFromHandler) NULL)
4964 cache_info->methods.get_authentic_indexes_from_handler=
4965 cache_methods->get_authentic_indexes_from_handler;
4966 get_one_virtual_pixel_from_handler=
4967 cache_info->methods.get_one_virtual_pixel_from_handler;
4968 if (get_one_virtual_pixel_from_handler !=
4969 (GetOneVirtualPixelFromHandler) NULL)
4970 cache_info->methods.get_one_virtual_pixel_from_handler=
4971 cache_methods->get_one_virtual_pixel_from_handler;
4972 get_one_authentic_pixel_from_handler=
4973 cache_methods->get_one_authentic_pixel_from_handler;
4974 if (get_one_authentic_pixel_from_handler !=
4975 (GetOneAuthenticPixelFromHandler) NULL)
4976 cache_info->methods.get_one_authentic_pixel_from_handler=
4977 cache_methods->get_one_authentic_pixel_from_handler;
4981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4985 + S e t P i x e l C a c h e N e x u s P i x e l s %
4989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4991 % SetPixelCacheNexusPixels() defines the region of the cache for the
4992 % specified cache nexus.
4994 % The format of the SetPixelCacheNexusPixels() method is:
4996 % PixelPacket SetPixelCacheNexusPixels(const Image *image,
4997 % const RectangleInfo *region,NexusInfo *nexus_info,
4998 % ExceptionInfo *exception)
5000 % A description of each parameter follows:
5002 % o image: the image.
5004 % o region: A pointer to the RectangleInfo structure that defines the
5005 % region of this particular cache nexus.
5007 % o nexus_info: the cache nexus to set.
5009 % o exception: return any errors or warnings in this structure.
5012 static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
5013 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
5025 cache_info=(CacheInfo *) image->cache;
5026 assert(cache_info->signature == MagickSignature);
5027 if (cache_info->type == UndefinedCache)
5028 return((PixelPacket *) NULL);
5029 nexus_info->region=(*region);
5030 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
5031 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
5037 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
5038 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
5039 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
5040 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5041 ((nexus_info->region.height == 1UL) ||
5042 ((nexus_info->region.x == 0) &&
5043 ((nexus_info->region.width == cache_info->columns) ||
5044 ((nexus_info->region.width % cache_info->columns) == 0)))))
5050 Pixels are accessed directly from memory.
5052 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5053 nexus_info->region.x;
5054 nexus_info->pixels=cache_info->pixels+offset;
5055 nexus_info->indexes=(IndexPacket *) NULL;
5056 if (cache_info->active_index_channel != MagickFalse)
5057 nexus_info->indexes=cache_info->indexes+offset;
5058 return(nexus_info->pixels);
5062 Pixels are stored in a cache region until they are synced to the cache.
5064 number_pixels=(MagickSizeType) nexus_info->region.width*
5065 nexus_info->region.height;
5066 length=number_pixels*sizeof(PixelPacket);
5067 if (cache_info->active_index_channel != MagickFalse)
5068 length+=number_pixels*sizeof(IndexPacket);
5069 if (nexus_info->cache == (PixelPacket *) NULL)
5071 nexus_info->length=length;
5072 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5073 if (status == MagickFalse)
5074 return((PixelPacket *) NULL);
5077 if (nexus_info->length != length)
5079 RelinquishCacheNexusPixels(nexus_info);
5080 nexus_info->length=length;
5081 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5082 if (status == MagickFalse)
5083 return((PixelPacket *) NULL);
5085 nexus_info->pixels=nexus_info->cache;
5086 nexus_info->indexes=(IndexPacket *) NULL;
5087 if (cache_info->active_index_channel != MagickFalse)
5088 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5089 return(nexus_info->pixels);
5093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5097 % 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 %
5101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5103 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5104 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5105 % access that is outside the boundaries of the image cache.
5107 % The format of the SetPixelCacheVirtualMethod() method is:
5109 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5110 % const VirtualPixelMethod virtual_pixel_method)
5112 % A description of each parameter follows:
5114 % o image: the image.
5116 % o virtual_pixel_method: choose the type of virtual pixel.
5119 MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5120 const VirtualPixelMethod virtual_pixel_method)
5128 assert(image != (Image *) NULL);
5129 assert(image->signature == MagickSignature);
5130 if (image->debug != MagickFalse)
5131 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5132 assert(image->cache != (Cache) NULL);
5133 cache_info=(CacheInfo *) image->cache;
5134 assert(cache_info->signature == MagickSignature);
5135 method=cache_info->virtual_pixel_method;
5136 cache_info->virtual_pixel_method=virtual_pixel_method;
5141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5145 + 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 %
5149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5151 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5152 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5153 % is synced, otherwise MagickFalse.
5155 % The format of the SyncAuthenticPixelCacheNexus() method is:
5157 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5158 % NexusInfo *nexus_info,ExceptionInfo *exception)
5160 % A description of each parameter follows:
5162 % o image: the image.
5164 % o nexus_info: the cache nexus to sync.
5166 % o exception: return any errors or warnings in this structure.
5169 MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5170 NexusInfo *nexus_info,ExceptionInfo *exception)
5179 Transfer pixels to the cache.
5181 assert(image != (Image *) NULL);
5182 assert(image->signature == MagickSignature);
5183 if (image->cache == (Cache) NULL)
5184 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5185 cache_info=(CacheInfo *) image->cache;
5186 if (cache_info->type == UndefinedCache)
5187 return(MagickFalse);
5188 if ((image->clip_mask != (Image *) NULL) &&
5189 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5190 return(MagickFalse);
5191 if ((image->mask != (Image *) NULL) &&
5192 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5193 return(MagickFalse);
5194 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5196 assert(cache_info->signature == MagickSignature);
5197 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5198 if ((cache_info->active_index_channel != MagickFalse) &&
5199 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5200 return(MagickFalse);
5205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5209 + S y n c A u t h e n t i c P i x e l C a c h e %
5213 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5215 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5216 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5217 % otherwise MagickFalse.
5219 % The format of the SyncAuthenticPixelsCache() method is:
5221 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5222 % ExceptionInfo *exception)
5224 % A description of each parameter follows:
5226 % o image: the image.
5228 % o exception: return any errors or warnings in this structure.
5231 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5232 ExceptionInfo *exception)
5243 cache_info=(CacheInfo *) image->cache;
5244 id=GetOpenMPThreadId();
5245 assert(id < (int) cache_info->number_threads);
5246 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5256 % S y n c A u t h e n t i c P i x e l s %
5260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5262 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5263 % The method returns MagickTrue if the pixel region is flushed, otherwise
5266 % The format of the SyncAuthenticPixels() method is:
5268 % MagickBooleanType SyncAuthenticPixels(Image *image,
5269 % ExceptionInfo *exception)
5271 % A description of each parameter follows:
5273 % o image: the image.
5275 % o exception: return any errors or warnings in this structure.
5278 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5279 ExceptionInfo *exception)
5284 assert(image != (Image *) NULL);
5285 assert(image->signature == MagickSignature);
5286 assert(image->cache != (Cache) NULL);
5287 cache_info=(CacheInfo *) image->cache;
5288 assert(cache_info->signature == MagickSignature);
5289 if (cache_info->methods.sync_authentic_pixels_handler ==
5290 (SyncAuthenticPixelsHandler) NULL)
5291 return(MagickFalse);
5292 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5300 + W r i t e P i x e l C a c h e I n d e x e s %
5304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5306 % WritePixelCacheIndexes() writes the colormap indexes to the specified
5307 % region of the pixel cache.
5309 % The format of the WritePixelCacheIndexes() method is:
5311 % MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5312 % NexusInfo *nexus_info,ExceptionInfo *exception)
5314 % A description of each parameter follows:
5316 % o cache_info: the pixel cache.
5318 % o nexus_info: the cache nexus to write the colormap indexes.
5320 % o exception: return any errors or warnings in this structure.
5323 static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5324 NexusInfo *nexus_info,ExceptionInfo *exception)
5334 register const IndexPacket
5343 if (cache_info->active_index_channel == MagickFalse)
5344 return(MagickFalse);
5345 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5347 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5348 nexus_info->region.x;
5349 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5350 rows=nexus_info->region.height;
5351 number_pixels=(MagickSizeType) length*rows;
5352 p=nexus_info->indexes;
5353 switch (cache_info->type)
5358 register IndexPacket
5362 Write indexes to memory.
5364 if ((cache_info->columns == nexus_info->region.width) &&
5365 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5367 length=number_pixels;
5370 q=cache_info->indexes+offset;
5371 for (y=0; y < (ssize_t) rows; y++)
5373 (void) CopyMagickMemory(q,p,(size_t) length);
5374 p+=nexus_info->region.width;
5375 q+=cache_info->columns;
5382 Write indexes to disk.
5384 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5386 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5387 cache_info->cache_filename);
5388 return(MagickFalse);
5390 if ((cache_info->columns == nexus_info->region.width) &&
5391 (number_pixels < MagickMaxBufferExtent))
5393 length=number_pixels;
5396 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5397 for (y=0; y < (ssize_t) rows; y++)
5399 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5400 sizeof(PixelPacket)+offset*sizeof(*p),length,
5401 (const unsigned char *) p);
5402 if ((MagickSizeType) count < length)
5404 p+=nexus_info->region.width;
5405 offset+=cache_info->columns;
5407 if (y < (ssize_t) rows)
5409 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5410 cache_info->cache_filename);
5411 return(MagickFalse);
5418 if ((cache_info->debug != MagickFalse) &&
5419 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5420 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5421 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5422 nexus_info->region.width,(double) nexus_info->region.height,(double)
5423 nexus_info->region.x,(double) nexus_info->region.y);
5428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5432 + W r i t e C a c h e P i x e l s %
5436 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5438 % WritePixelCachePixels() writes image pixels to the specified region of the
5441 % The format of the WritePixelCachePixels() method is:
5443 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5444 % NexusInfo *nexus_info,ExceptionInfo *exception)
5446 % A description of each parameter follows:
5448 % o cache_info: the pixel cache.
5450 % o nexus_info: the cache nexus to write the pixels.
5452 % o exception: return any errors or warnings in this structure.
5455 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5456 NexusInfo *nexus_info,ExceptionInfo *exception)
5466 register const PixelPacket
5475 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5477 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5478 nexus_info->region.x;
5479 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5480 rows=nexus_info->region.height;
5481 number_pixels=length*rows;
5482 p=nexus_info->pixels;
5483 switch (cache_info->type)
5488 register PixelPacket
5492 Write pixels to memory.
5494 if ((cache_info->columns == nexus_info->region.width) &&
5495 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5497 length=number_pixels;
5500 q=cache_info->pixels+offset;
5501 for (y=0; y < (ssize_t) rows; y++)
5503 (void) CopyMagickMemory(q,p,(size_t) length);
5504 p+=nexus_info->region.width;
5505 q+=cache_info->columns;
5512 Write pixels to disk.
5514 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5516 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5517 cache_info->cache_filename);
5518 return(MagickFalse);
5520 if ((cache_info->columns == nexus_info->region.width) &&
5521 (number_pixels < MagickMaxBufferExtent))
5523 length=number_pixels;
5526 for (y=0; y < (ssize_t) rows; y++)
5528 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5529 sizeof(*p),length,(const unsigned char *) p);
5530 if ((MagickSizeType) count < length)
5532 p+=nexus_info->region.width;
5533 offset+=cache_info->columns;
5535 if (y < (ssize_t) rows)
5537 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5538 cache_info->cache_filename);
5539 return(MagickFalse);
5546 if ((cache_info->debug != MagickFalse) &&
5547 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5548 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5549 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5550 nexus_info->region.width,(double) nexus_info->region.height,(double)
5551 nexus_info->region.x,(double) nexus_info->region.y);