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 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
127 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
128 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
129 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
130 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
131 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
134 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
135 const size_t,ExceptionInfo *),
136 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
139 #if defined(__cplusplus) || defined(c_plusplus)
146 static volatile MagickBooleanType
147 instantiate_cache = MagickFalse;
150 *cache_semaphore = (SemaphoreInfo *) NULL;
153 *cache_resources = (SplayTreeInfo *) NULL;
156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
160 + A c q u i r e P i x e l C a c h e %
164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166 % AcquirePixelCache() acquires a pixel cache.
168 % The format of the AcquirePixelCache() method is:
170 % Cache AcquirePixelCache(const size_t number_threads)
172 % A description of each parameter follows:
174 % o number_threads: the number of nexus threads.
177 MagickExport Cache AcquirePixelCache(const size_t number_threads)
182 cache_info=(CacheInfo *) AcquireAlignedMemory(1,sizeof(*cache_info));
183 if (cache_info == (CacheInfo *) NULL)
184 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
185 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
186 cache_info->type=UndefinedCache;
187 cache_info->mode=IOMode;
188 cache_info->colorspace=RGBColorspace;
189 cache_info->file=(-1);
190 cache_info->id=GetMagickThreadId();
191 cache_info->number_threads=number_threads;
192 if (number_threads == 0)
193 cache_info->number_threads=GetOpenMPMaximumThreads();
194 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
195 if (cache_info->nexus_info == (NexusInfo **) NULL)
196 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
197 cache_info->semaphore=AllocateSemaphoreInfo();
198 cache_info->reference_count=1;
199 cache_info->disk_semaphore=AllocateSemaphoreInfo();
200 cache_info->debug=IsEventLogging();
201 cache_info->signature=MagickSignature;
202 if ((cache_resources == (SplayTreeInfo *) NULL) &&
203 (instantiate_cache == MagickFalse))
205 if (cache_semaphore == (SemaphoreInfo *) NULL)
206 AcquireSemaphoreInfo(&cache_semaphore);
207 LockSemaphoreInfo(cache_semaphore);
208 if ((cache_resources == (SplayTreeInfo *) NULL) &&
209 (instantiate_cache == MagickFalse))
211 cache_resources=NewSplayTree((int (*)(const void *,const void *))
212 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
213 instantiate_cache=MagickTrue;
215 UnlockSemaphoreInfo(cache_semaphore);
217 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
218 return((Cache ) cache_info);
222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
226 % A c q u i r e P i x e l C a c h e N e x u s %
230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
234 % The format of the AcquirePixelCacheNexus method is:
236 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
238 % A description of each parameter follows:
240 % o number_threads: the number of nexus threads.
243 MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
251 nexus_info=(NexusInfo **) AcquireAlignedMemory(number_threads,
252 sizeof(*nexus_info));
253 if (nexus_info == (NexusInfo **) NULL)
254 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
255 for (i=0; i < (ssize_t) number_threads; i++)
257 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
258 if (nexus_info[i] == (NexusInfo *) NULL)
259 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
260 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
261 nexus_info[i]->signature=MagickSignature;
267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271 + A c q u i r e P i x e l C a c h e P i x e l s %
275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277 % AcquirePixelCachePixels() returns the pixels associated with the specified
280 % The format of the AcquirePixelCachePixels() method is:
282 % const void *AcquirePixelCachePixels(const Image *image,
283 % MagickSizeType *length,ExceptionInfo *exception)
285 % A description of each parameter follows:
287 % o image: the image.
289 % o length: the pixel cache length.
291 % o exception: return any errors or warnings in this structure.
294 MagickExport const void *AcquirePixelCachePixels(const Image *image,
295 MagickSizeType *length,ExceptionInfo *exception)
300 assert(image != (const Image *) NULL);
301 assert(image->signature == MagickSignature);
302 assert(exception != (ExceptionInfo *) NULL);
303 assert(exception->signature == MagickSignature);
304 assert(image->cache != (Cache) NULL);
305 cache_info=(CacheInfo *) image->cache;
306 assert(cache_info->signature == MagickSignature);
308 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
309 return((const void *) NULL);
310 *length=cache_info->length;
311 return((const void *) cache_info->pixels);
315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319 + C a c h e C o m p o n e n t G e n e s i s %
323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325 % CacheComponentGenesis() instantiates the cache component.
327 % The format of the CacheComponentGenesis method is:
329 % MagickBooleanType CacheComponentGenesis(void)
332 MagickExport MagickBooleanType CacheComponentGenesis(void)
334 AcquireSemaphoreInfo(&cache_semaphore);
339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343 + C a c h e C o m p o n e n t T e r m i n u s %
347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
349 % CacheComponentTerminus() destroys the cache component.
351 % The format of the CacheComponentTerminus() method is:
353 % CacheComponentTerminus(void)
356 MagickExport void CacheComponentTerminus(void)
358 if (cache_semaphore == (SemaphoreInfo *) NULL)
359 AcquireSemaphoreInfo(&cache_semaphore);
360 LockSemaphoreInfo(cache_semaphore);
361 if (cache_resources != (SplayTreeInfo *) NULL)
362 cache_resources=DestroySplayTree(cache_resources);
363 instantiate_cache=MagickFalse;
364 UnlockSemaphoreInfo(cache_semaphore);
365 DestroySemaphoreInfo(&cache_semaphore);
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373 + C l i p P i x e l C a c h e N e x u s %
377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379 % ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
380 % mask. The method returns MagickTrue if the pixel region is clipped,
381 % otherwise MagickFalse.
383 % The format of the ClipPixelCacheNexus() method is:
385 % MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
386 % ExceptionInfo *exception)
388 % A description of each parameter follows:
390 % o image: the image.
392 % o nexus_info: the cache nexus to clip.
394 % o exception: return any errors or warnings in this structure.
397 static MagickBooleanType ClipPixelCacheNexus(Image *image,
398 NexusInfo *nexus_info,ExceptionInfo *exception)
410 register const PixelPacket
414 *restrict nexus_indexes,
427 if (image->debug != MagickFalse)
428 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
429 if (image->clip_mask == (Image *) NULL)
431 cache_info=(CacheInfo *) image->cache;
432 if (cache_info == (Cache) NULL)
434 image_nexus=AcquirePixelCacheNexus(1);
435 clip_nexus=AcquirePixelCacheNexus(1);
436 if ((image_nexus == (NexusInfo **) NULL) ||
437 (clip_nexus == (NexusInfo **) NULL))
438 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
439 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
440 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
442 indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
443 q=nexus_info->pixels;
444 nexus_indexes=nexus_info->indexes;
445 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
446 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
447 nexus_info->region.height,clip_nexus[0],exception);
448 number_pixels=(MagickSizeType) nexus_info->region.width*
449 nexus_info->region.height;
450 for (i=0; i < (ssize_t) number_pixels; i++)
452 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
454 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
456 SetRedPixelComponent(q,GetRedPixelComponent(p));
457 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
458 SetBluePixelComponent(q,GetBluePixelComponent(p));
459 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
460 if (cache_info->active_index_channel != MagickFalse)
461 nexus_indexes[i]=indexes[i];
467 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
468 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
469 if (i < (ssize_t) number_pixels)
475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
479 + C l o n e P i x e l C a c h e %
483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 % ClonePixelCache() clones a pixel cache.
487 % The format of the ClonePixelCache() method is:
489 % Cache ClonePixelCache(const Cache cache)
491 % A description of each parameter follows:
493 % o cache: the pixel cache.
496 MagickExport Cache ClonePixelCache(const Cache cache)
504 assert(cache != (const Cache) NULL);
505 cache_info=(const CacheInfo *) cache;
506 assert(cache_info->signature == MagickSignature);
507 if (cache_info->debug != MagickFalse)
508 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
509 cache_info->filename);
510 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
511 if (clone_info == (Cache) NULL)
512 return((Cache) NULL);
513 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
514 return((Cache ) clone_info);
518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
522 + C l o n e P i x e l C a c h e P i x e l s %
526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
527 % ClonePixelCachePixels() clones the source pixel cache to the destination
530 % The format of the ClonePixelCachePixels() method is:
532 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
533 % CacheInfo *source_info,ExceptionInfo *exception)
535 % A description of each parameter follows:
537 % o cache_info: the pixel cache.
539 % o source_info: the source pixel cache.
541 % o exception: return any errors or warnings in this structure.
545 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
551 LockSemaphoreInfo(cache_info->disk_semaphore);
552 if (cache_info->file != -1)
553 status=close(cache_info->file);
554 cache_info->file=(-1);
555 RelinquishMagickResource(FileResource,1);
556 UnlockSemaphoreInfo(cache_info->disk_semaphore);
557 return(status == -1 ? MagickFalse : MagickTrue);
560 static void LimitPixelCacheDescriptors(void)
567 Limit # of open file descriptors.
569 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
571 LockSemaphoreInfo(cache_semaphore);
572 if (cache_resources == (SplayTreeInfo *) NULL)
574 UnlockSemaphoreInfo(cache_semaphore);
577 ResetSplayTreeIterator(cache_resources);
578 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
579 while (p != (CacheInfo *) NULL)
581 if ((p->type == DiskCache) && (p->file != -1))
583 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
585 for (q=p; p != (CacheInfo *) NULL; )
587 if ((p->type == DiskCache) && (p->file != -1) &&
588 (p->timestamp < q->timestamp))
590 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
592 if (q != (CacheInfo *) NULL)
595 Close least recently used cache.
597 (void) close(q->file);
600 UnlockSemaphoreInfo(cache_semaphore);
603 static inline MagickSizeType MagickMax(const MagickSizeType x,
604 const MagickSizeType y)
611 static inline MagickSizeType MagickMin(const MagickSizeType x,
612 const MagickSizeType y)
619 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
626 Open pixel cache on disk.
628 LockSemaphoreInfo(cache_info->disk_semaphore);
629 if (cache_info->file != -1)
631 UnlockSemaphoreInfo(cache_info->disk_semaphore);
632 return(MagickTrue); /* cache already open */
634 LimitPixelCacheDescriptors();
635 if (*cache_info->cache_filename == '\0')
636 file=AcquireUniqueFileResource(cache_info->cache_filename);
642 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
647 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
650 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
656 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
659 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
665 UnlockSemaphoreInfo(cache_info->disk_semaphore);
668 (void) AcquireMagickResource(FileResource,1);
669 cache_info->file=file;
670 cache_info->timestamp=time(0);
671 UnlockSemaphoreInfo(cache_info->disk_semaphore);
675 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
676 const MagickOffsetType offset,const MagickSizeType length,
677 unsigned char *restrict buffer)
679 register MagickOffsetType
685 cache_info->timestamp=time(0);
686 #if !defined(MAGICKCORE_HAVE_PREAD)
687 LockSemaphoreInfo(cache_info->disk_semaphore);
688 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
690 UnlockSemaphoreInfo(cache_info->disk_semaphore);
691 return((MagickOffsetType) -1);
695 for (i=0; i < (MagickOffsetType) length; i+=count)
697 #if !defined(MAGICKCORE_HAVE_PREAD)
698 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
699 (MagickSizeType) SSIZE_MAX));
701 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
702 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
713 #if !defined(MAGICKCORE_HAVE_PREAD)
714 UnlockSemaphoreInfo(cache_info->disk_semaphore);
719 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
720 const MagickOffsetType offset,const MagickSizeType length,
721 const unsigned char *restrict buffer)
723 register MagickOffsetType
729 cache_info->timestamp=time(0);
730 #if !defined(MAGICKCORE_HAVE_PWRITE)
731 LockSemaphoreInfo(cache_info->disk_semaphore);
732 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
734 UnlockSemaphoreInfo(cache_info->disk_semaphore);
735 return((MagickOffsetType) -1);
739 for (i=0; i < (MagickOffsetType) length; i+=count)
741 #if !defined(MAGICKCORE_HAVE_PWRITE)
742 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
743 (MagickSizeType) SSIZE_MAX));
745 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
746 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
757 #if !defined(MAGICKCORE_HAVE_PWRITE)
758 UnlockSemaphoreInfo(cache_info->disk_semaphore);
763 static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
764 CacheInfo *cache_info,ExceptionInfo *exception)
784 if (cache_info->debug != MagickFalse)
785 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
786 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
788 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
789 clone_info->cache_filename);
792 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 cache_info->cache_filename);
798 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
799 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
800 if ((clone_info->active_index_channel != MagickFalse) &&
801 (cache_info->active_index_channel != MagickFalse))
809 length=MagickMax(clone_info->columns,cache_info->columns)*
811 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
812 if (indexes == (IndexPacket *) NULL)
814 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
815 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
818 (void) ResetMagickMemory(indexes,0,(size_t) length);
819 length=columns*sizeof(*indexes);
820 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
821 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
822 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
823 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
824 for (y=0; y < (ssize_t) rows; y++)
826 source_offset-=cache_info->columns*sizeof(*indexes);
827 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
828 length,(unsigned char *) indexes);
829 if ((MagickSizeType) count != length)
831 offset-=clone_info->columns*sizeof(*indexes);
832 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
833 (unsigned char *) indexes);
834 if ((MagickSizeType) count != length)
837 if (y < (ssize_t) rows)
839 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
840 ThrowFileException(exception,CacheError,"UnableToCloneCache",
841 cache_info->cache_filename);
844 if (clone_info->columns > cache_info->columns)
846 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
847 (void) ResetMagickMemory(indexes,0,(size_t) length);
848 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
849 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
850 for (y=0; y < (ssize_t) rows; y++)
852 offset-=clone_info->columns*sizeof(*indexes);
853 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
854 length,(unsigned char *) indexes);
855 if ((MagickSizeType) count != length)
858 if (y < (ssize_t) rows)
860 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
861 ThrowFileException(exception,CacheError,"UnableToCloneCache",
862 cache_info->cache_filename);
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
871 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
872 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
873 if (pixels == (PixelPacket *) NULL)
875 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
876 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
879 (void) ResetMagickMemory(pixels,0,(size_t) length);
880 length=columns*sizeof(*pixels);
881 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
882 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
883 for (y=0; y < (ssize_t) rows; y++)
885 source_offset-=cache_info->columns*sizeof(*pixels);
886 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
887 length,(unsigned char *) pixels);
888 if ((MagickSizeType) count != length)
890 offset-=clone_info->columns*sizeof(*pixels);
891 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
892 (unsigned char *) pixels);
893 if ((MagickSizeType) count != length)
896 if (y < (ssize_t) rows)
898 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
899 ThrowFileException(exception,CacheError,"UnableToCloneCache",
900 cache_info->cache_filename);
903 if (clone_info->columns > cache_info->columns)
905 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
907 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
908 (void) ResetMagickMemory(pixels,0,(size_t) length);
909 for (y=0; y < (ssize_t) rows; y++)
911 offset-=clone_info->columns*sizeof(*pixels);
912 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
913 (unsigned char *) pixels);
914 if ((MagickSizeType) count != length)
917 if (y < (ssize_t) rows)
919 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
920 ThrowFileException(exception,CacheError,"UnableToCloneCache",
921 cache_info->cache_filename);
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
929 static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
930 CacheInfo *cache_info,ExceptionInfo *exception)
950 if (cache_info->debug != MagickFalse)
951 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
952 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
954 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
955 cache_info->cache_filename);
958 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
959 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
960 if ((clone_info->active_index_channel != MagickFalse) &&
961 (cache_info->active_index_channel != MagickFalse))
970 length=MagickMax(clone_info->columns,cache_info->columns)*
972 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
973 if (indexes == (IndexPacket *) NULL)
975 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
976 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
979 (void) ResetMagickMemory(indexes,0,(size_t) length);
980 length=columns*sizeof(IndexPacket);
981 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
982 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
983 q=clone_info->indexes+clone_info->columns*rows;
984 for (y=0; y < (ssize_t) rows; y++)
986 offset-=cache_info->columns*sizeof(IndexPacket);
987 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
988 length,(unsigned char *) indexes);
989 if ((MagickSizeType) count != length)
991 q-=clone_info->columns;
992 (void) memcpy(q,indexes,(size_t) length);
993 if ((MagickSizeType) count != length)
996 if (y < (ssize_t) rows)
998 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
999 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1000 cache_info->cache_filename);
1001 return(MagickFalse);
1003 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1008 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1009 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1010 if (pixels == (PixelPacket *) NULL)
1012 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1013 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1014 return(MagickFalse);
1016 (void) ResetMagickMemory(pixels,0,(size_t) length);
1017 length=columns*sizeof(*pixels);
1018 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1019 q=clone_info->pixels+clone_info->columns*rows;
1020 for (y=0; y < (ssize_t) rows; y++)
1022 offset-=cache_info->columns*sizeof(*pixels);
1023 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1024 (unsigned char *) pixels);
1025 if ((MagickSizeType) count != length)
1027 q-=clone_info->columns;
1028 (void) memcpy(q,pixels,(size_t) length);
1030 if (y < (ssize_t) rows)
1032 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1033 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1034 cache_info->cache_filename);
1035 return(MagickFalse);
1037 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1041 static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1042 CacheInfo *cache_info,ExceptionInfo *exception)
1051 register PixelPacket
1062 if (cache_info->debug != MagickFalse)
1063 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1064 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1066 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1067 clone_info->cache_filename);
1068 return(MagickFalse);
1070 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1071 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1072 if ((clone_info->active_index_channel != MagickFalse) &&
1073 (cache_info->active_index_channel != MagickFalse))
1075 register IndexPacket
1080 Clone cache indexes.
1082 length=MagickMax(clone_info->columns,cache_info->columns)*
1084 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1085 if (indexes == (IndexPacket *) NULL)
1087 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1088 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1089 return(MagickFalse);
1091 (void) ResetMagickMemory(indexes,0,(size_t) length);
1092 length=columns*sizeof(*indexes);
1093 p=cache_info->indexes+cache_info->columns*rows;
1094 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1095 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
1096 for (y=0; y < (ssize_t) rows; y++)
1098 p-=cache_info->columns;
1099 (void) memcpy(indexes,p,(size_t) length);
1100 offset-=clone_info->columns*sizeof(*indexes);
1101 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1102 (unsigned char *) indexes);
1103 if ((MagickSizeType) count != length)
1106 if (y < (ssize_t) rows)
1108 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1109 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1110 cache_info->cache_filename);
1111 return(MagickFalse);
1113 if (clone_info->columns > cache_info->columns)
1115 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1116 (void) ResetMagickMemory(indexes,0,(size_t) length);
1117 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1118 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
1119 for (y=0; y < (ssize_t) rows; y++)
1121 offset-=clone_info->columns*sizeof(*indexes);
1122 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1123 length,(unsigned char *) indexes);
1124 if ((MagickSizeType) count != length)
1127 if (y < (ssize_t) rows)
1129 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1130 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1131 cache_info->cache_filename);
1132 return(MagickFalse);
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1140 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1141 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1142 if (pixels == (PixelPacket *) NULL)
1144 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1145 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1146 return(MagickFalse);
1148 (void) ResetMagickMemory(pixels,0,(size_t) length);
1149 length=columns*sizeof(*pixels);
1150 p=cache_info->pixels+cache_info->columns*rows;
1151 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
1152 for (y=0; y < (ssize_t) rows; y++)
1154 p-=cache_info->columns;
1155 (void) memcpy(pixels,p,(size_t) length);
1156 offset-=clone_info->columns*sizeof(*pixels);
1157 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1158 (unsigned char *) pixels);
1159 if ((MagickSizeType) count != length)
1162 if (y < (ssize_t) rows)
1164 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1165 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1166 cache_info->cache_filename);
1167 return(MagickFalse);
1169 if (clone_info->columns > cache_info->columns)
1171 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1173 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1174 (void) ResetMagickMemory(pixels,0,(size_t) length);
1175 for (y=0; y < (ssize_t) rows; y++)
1177 offset-=clone_info->columns*sizeof(*pixels);
1178 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1179 (unsigned char *) pixels);
1180 if ((MagickSizeType) count != length)
1183 if (y < (ssize_t) rows)
1185 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1186 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1187 cache_info->cache_filename);
1188 return(MagickFalse);
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1195 static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1196 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1198 register PixelPacket
1200 *restrict source_pixels;
1210 if (cache_info->debug != MagickFalse)
1211 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
1212 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1213 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1214 if ((clone_info->active_index_channel != MagickFalse) &&
1215 (cache_info->active_index_channel != MagickFalse))
1217 register IndexPacket
1222 Clone cache indexes.
1224 length=columns*sizeof(*indexes);
1225 if (clone_info->columns == cache_info->columns)
1226 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
1229 source_indexes=cache_info->indexes+cache_info->columns*rows;
1230 indexes=clone_info->indexes+clone_info->columns*rows;
1231 for (y=0; y < (ssize_t) rows; y++)
1233 source_indexes-=cache_info->columns;
1234 indexes-=clone_info->columns;
1235 (void) memcpy(indexes,source_indexes,length);
1237 if (clone_info->columns > cache_info->columns)
1239 length=(clone_info->columns-cache_info->columns)*
1241 indexes=clone_info->indexes+clone_info->columns*rows+
1242 cache_info->columns;
1243 for (y=0; y < (ssize_t) rows; y++)
1245 indexes-=clone_info->columns;
1246 (void) ResetMagickMemory(indexes,0,length);
1254 length=columns*sizeof(*pixels);
1255 if (clone_info->columns == cache_info->columns)
1256 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
1259 source_pixels=cache_info->pixels+cache_info->columns*rows;
1260 pixels=clone_info->pixels+clone_info->columns*rows;
1261 for (y=0; y < (ssize_t) rows; y++)
1263 source_pixels-=cache_info->columns;
1264 pixels-=clone_info->columns;
1265 (void) memcpy(pixels,source_pixels,length);
1267 if (clone_info->columns > cache_info->columns)
1269 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1270 pixels=clone_info->pixels+clone_info->columns*rows+
1271 cache_info->columns;
1272 for (y=0; y < (ssize_t) rows; y++)
1274 pixels-=clone_info->columns;
1275 (void) ResetMagickMemory(pixels,0,length);
1282 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1283 CacheInfo *cache_info,ExceptionInfo *exception)
1285 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1286 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1287 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1288 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1289 if (cache_info->type == DiskCache)
1290 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1291 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1299 + C l o n e P i x e l C a c h e M e t h o d s %
1303 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1308 % The format of the ClonePixelCacheMethods() method is:
1310 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1312 % A description of each parameter follows:
1314 % o clone: Specifies a pointer to a Cache structure.
1316 % o cache: the pixel cache.
1319 MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1325 assert(clone != (Cache) NULL);
1326 source_info=(CacheInfo *) clone;
1327 assert(source_info->signature == MagickSignature);
1328 if (source_info->debug != MagickFalse)
1329 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1330 source_info->filename);
1331 assert(cache != (Cache) NULL);
1332 cache_info=(CacheInfo *) cache;
1333 assert(cache_info->signature == MagickSignature);
1334 source_info->methods=cache_info->methods;
1338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1342 + D e s t r o y I m a g e P i x e l C a c h e %
1346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1348 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1350 % The format of the DestroyImagePixelCache() method is:
1352 % void DestroyImagePixelCache(Image *image)
1354 % A description of each parameter follows:
1356 % o image: the image.
1359 static void DestroyImagePixelCache(Image *image)
1361 assert(image != (Image *) NULL);
1362 assert(image->signature == MagickSignature);
1363 if (image->debug != MagickFalse)
1364 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1365 if (image->cache == (void *) NULL)
1367 image->cache=DestroyPixelCache(image->cache);
1371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1375 + D e s t r o y I m a g e P i x e l s %
1379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1383 % The format of the DestroyImagePixels() method is:
1385 % void DestroyImagePixels(Image *image)
1387 % A description of each parameter follows:
1389 % o image: the image.
1392 MagickExport void DestroyImagePixels(Image *image)
1397 assert(image != (const Image *) NULL);
1398 assert(image->signature == MagickSignature);
1399 if (image->debug != MagickFalse)
1400 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1401 assert(image->cache != (Cache) NULL);
1402 cache_info=(CacheInfo *) image->cache;
1403 assert(cache_info->signature == MagickSignature);
1404 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1406 cache_info->methods.destroy_pixel_handler(image);
1409 image->cache=DestroyPixelCache(image->cache);
1413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1417 + D e s t r o y P i x e l C a c h e %
1421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1425 % The format of the DestroyPixelCache() method is:
1427 % Cache DestroyPixelCache(Cache cache)
1429 % A description of each parameter follows:
1431 % o cache: the pixel cache.
1435 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1437 switch (cache_info->type)
1441 if (cache_info->mapped == MagickFalse)
1442 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1443 cache_info->pixels);
1445 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1446 (size_t) cache_info->length);
1447 RelinquishMagickResource(MemoryResource,cache_info->length);
1452 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1453 cache_info->length);
1454 RelinquishMagickResource(MapResource,cache_info->length);
1458 if (cache_info->file != -1)
1459 (void) ClosePixelCacheOnDisk(cache_info);
1460 RelinquishMagickResource(DiskResource,cache_info->length);
1466 cache_info->type=UndefinedCache;
1467 cache_info->mapped=MagickFalse;
1468 cache_info->indexes=(IndexPacket *) NULL;
1471 MagickExport Cache DestroyPixelCache(Cache cache)
1476 assert(cache != (Cache) NULL);
1477 cache_info=(CacheInfo *) cache;
1478 assert(cache_info->signature == MagickSignature);
1479 if (cache_info->debug != MagickFalse)
1480 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1481 cache_info->filename);
1482 LockSemaphoreInfo(cache_info->semaphore);
1483 cache_info->reference_count--;
1484 if (cache_info->reference_count != 0)
1486 UnlockSemaphoreInfo(cache_info->semaphore);
1487 return((Cache) NULL);
1489 UnlockSemaphoreInfo(cache_info->semaphore);
1490 if (cache_resources != (SplayTreeInfo *) NULL)
1491 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1492 if (cache_info->debug != MagickFalse)
1495 message[MaxTextExtent];
1497 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1498 cache_info->filename);
1499 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1501 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1502 (cache_info->type != DiskCache)))
1503 RelinquishPixelCachePixels(cache_info);
1506 RelinquishPixelCachePixels(cache_info);
1507 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1509 *cache_info->cache_filename='\0';
1510 if (cache_info->nexus_info != (NexusInfo **) NULL)
1511 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1512 cache_info->number_threads);
1513 if (cache_info->random_info != (RandomInfo *) NULL)
1514 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1515 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1516 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1517 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1518 DestroySemaphoreInfo(&cache_info->semaphore);
1519 cache_info->signature=(~MagickSignature);
1520 cache_info=(CacheInfo *) RelinquishAlignedMemory(cache_info);
1526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1530 + D e s t r o y P i x e l C a c h e N e x u s %
1534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1538 % The format of the DestroyPixelCacheNexus() method is:
1540 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1541 % const size_t number_threads)
1543 % A description of each parameter follows:
1545 % o nexus_info: the nexus to destroy.
1547 % o number_threads: the number of nexus threads.
1551 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1553 if (nexus_info->mapped == MagickFalse)
1554 (void) RelinquishMagickMemory(nexus_info->cache);
1556 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1557 nexus_info->cache=(PixelPacket *) NULL;
1558 nexus_info->pixels=(PixelPacket *) NULL;
1559 nexus_info->indexes=(IndexPacket *) NULL;
1560 nexus_info->length=0;
1561 nexus_info->mapped=MagickFalse;
1564 MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1565 const size_t number_threads)
1570 assert(nexus_info != (NexusInfo **) NULL);
1571 for (i=0; i < (ssize_t) number_threads; i++)
1573 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1574 RelinquishCacheNexusPixels(nexus_info[i]);
1575 nexus_info[i]->signature=(~MagickSignature);
1576 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1578 nexus_info=(NexusInfo **) RelinquishAlignedMemory(nexus_info);
1583 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587 + 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 %
1591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593 % GetAuthenticIndexesFromCache() returns the indexes associated with the last
1594 % call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1596 % The format of the GetAuthenticIndexesFromCache() method is:
1598 % IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1600 % A description of each parameter follows:
1602 % o image: the image.
1605 static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1611 id = GetOpenMPThreadId();
1613 cache_info=(CacheInfo *) image->cache;
1614 assert(id < (int) cache_info->number_threads);
1615 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
1619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623 % G e t A u t h e n t i c I n d e x Q u e u e %
1627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1629 % GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1630 % indexes associated with the last call to QueueAuthenticPixels() or
1631 % GetVirtualPixels(). NULL is returned if the black channel or colormap
1632 % indexes are not available.
1634 % The format of the GetAuthenticIndexQueue() method is:
1636 % IndexPacket *GetAuthenticIndexQueue(const Image *image)
1638 % A description of each parameter follows:
1640 % o image: the image.
1643 MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1649 id = GetOpenMPThreadId();
1651 assert(image != (const Image *) NULL);
1652 assert(image->signature == MagickSignature);
1653 assert(image->cache != (Cache) NULL);
1654 cache_info=(CacheInfo *) image->cache;
1655 assert(cache_info->signature == MagickSignature);
1656 if (cache_info->methods.get_authentic_indexes_from_handler !=
1657 (GetAuthenticIndexesFromHandler) NULL)
1658 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1659 assert(id < (int) cache_info->number_threads);
1660 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
1664 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1668 + 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 %
1672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1674 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1675 % disk pixel cache as defined by the geometry parameters. A pointer to the
1676 % pixels is returned if the pixels are transferred, otherwise a NULL is
1679 % The format of the GetAuthenticPixelCacheNexus() method is:
1681 % PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1682 % const ssize_t y,const size_t columns,const size_t rows,
1683 % NexusInfo *nexus_info,ExceptionInfo *exception)
1685 % A description of each parameter follows:
1687 % o image: the image.
1689 % o x,y,columns,rows: These values define the perimeter of a region of
1692 % o nexus_info: the cache nexus to return.
1694 % o exception: return any errors or warnings in this structure.
1698 static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1699 NexusInfo *nexus_info)
1704 if (cache_info->type == PingCache)
1706 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1707 nexus_info->region.x;
1708 if (nexus_info->pixels != (cache_info->pixels+offset))
1709 return(MagickFalse);
1713 MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1714 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1715 NexusInfo *nexus_info,ExceptionInfo *exception)
1724 Transfer pixels from the cache.
1726 assert(image != (Image *) NULL);
1727 assert(image->signature == MagickSignature);
1728 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1729 if (pixels == (PixelPacket *) NULL)
1730 return((PixelPacket *) NULL);
1731 cache_info=(CacheInfo *) image->cache;
1732 assert(cache_info->signature == MagickSignature);
1733 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1735 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1736 return((PixelPacket *) NULL);
1737 if (cache_info->active_index_channel != MagickFalse)
1738 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1739 return((PixelPacket *) NULL);
1744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1748 + 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 %
1752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1754 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1755 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1757 % The format of the GetAuthenticPixelsFromCache() method is:
1759 % PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1761 % A description of each parameter follows:
1763 % o image: the image.
1766 static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1772 id = GetOpenMPThreadId();
1774 cache_info=(CacheInfo *) image->cache;
1775 assert(id < (int) cache_info->number_threads);
1776 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1784 % G e t A u t h e n t i c P i x e l Q u e u e %
1788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1790 % GetAuthenticPixelQueue() returns the authentic pixels associated with the
1791 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
1793 % The format of the GetAuthenticPixelQueue() method is:
1795 % PixelPacket *GetAuthenticPixelQueue(const Image image)
1797 % A description of each parameter follows:
1799 % o image: the image.
1802 MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1808 id = GetOpenMPThreadId();
1810 assert(image != (const Image *) NULL);
1811 assert(image->signature == MagickSignature);
1812 assert(image->cache != (Cache) NULL);
1813 cache_info=(CacheInfo *) image->cache;
1814 assert(cache_info->signature == MagickSignature);
1815 if (cache_info->methods.get_authentic_pixels_from_handler !=
1816 (GetAuthenticPixelsFromHandler) NULL)
1817 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1818 assert(id < (int) cache_info->number_threads);
1819 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1823 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1827 % G e t A u t h e n t i c P i x e l s %
1831 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1833 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1834 % region is successfully accessed, a pointer to a PixelPacket array
1835 % representing the region is returned, otherwise NULL is returned.
1837 % The returned pointer may point to a temporary working copy of the pixels
1838 % or it may point to the original pixels in memory. Performance is maximized
1839 % if the selected region is part of one row, or one or more full rows, since
1840 % then there is opportunity to access the pixels in-place (without a copy)
1841 % if the image is in memory, or in a memory-mapped file. The returned pointer
1842 % must *never* be deallocated by the user.
1844 % Pixels accessed via the returned pointer represent a simple array of type
1845 % PixelPacket. If the image type is CMYK or if the storage class is
1846 % PseduoClass, call GetAuthenticIndexQueue() after invoking
1847 % GetAuthenticPixels() to obtain the black color component or colormap indexes
1848 % (of type IndexPacket) corresponding to the region. Once the PixelPacket
1849 % (and/or IndexPacket) array has been updated, the changes must be saved back
1850 % to the underlying image using SyncAuthenticPixels() or they may be lost.
1852 % The format of the GetAuthenticPixels() method is:
1854 % PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1855 % const ssize_t y,const size_t columns,const size_t rows,
1856 % ExceptionInfo *exception)
1858 % A description of each parameter follows:
1860 % o image: the image.
1862 % o x,y,columns,rows: These values define the perimeter of a region of
1865 % o exception: return any errors or warnings in this structure.
1868 MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1869 const ssize_t y,const size_t columns,const size_t rows,
1870 ExceptionInfo *exception)
1876 id = GetOpenMPThreadId();
1878 assert(image != (Image *) NULL);
1879 assert(image->signature == MagickSignature);
1880 assert(image->cache != (Cache) NULL);
1881 cache_info=(CacheInfo *) image->cache;
1882 assert(cache_info->signature == MagickSignature);
1883 if (cache_info->methods.get_authentic_pixels_handler !=
1884 (GetAuthenticPixelsHandler) NULL)
1885 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1887 assert(id < (int) cache_info->number_threads);
1888 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1889 cache_info->nexus_info[id],exception));
1893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1897 + G e t A u t h e n t i c P i x e l s C a c h e %
1901 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1903 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1904 % as defined by the geometry parameters. A pointer to the pixels is returned
1905 % if the pixels are transferred, otherwise a NULL is returned.
1907 % The format of the GetAuthenticPixelsCache() method is:
1909 % PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1910 % const ssize_t y,const size_t columns,const size_t rows,
1911 % ExceptionInfo *exception)
1913 % A description of each parameter follows:
1915 % o image: the image.
1917 % o x,y,columns,rows: These values define the perimeter of a region of
1920 % o exception: return any errors or warnings in this structure.
1923 static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1924 const ssize_t y,const size_t columns,const size_t rows,
1925 ExceptionInfo *exception)
1931 id = GetOpenMPThreadId();
1933 cache_info=(CacheInfo *) image->cache;
1934 if (cache_info == (Cache) NULL)
1935 return((PixelPacket *) NULL);
1936 assert(id < (int) cache_info->number_threads);
1937 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1938 cache_info->nexus_info[id],exception));
1942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1946 + G e t I m a g e E x t e n t %
1950 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1952 % GetImageExtent() returns the extent of the pixels associated with the
1953 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
1955 % The format of the GetImageExtent() method is:
1957 % MagickSizeType GetImageExtent(const Image *image)
1959 % A description of each parameter follows:
1961 % o image: the image.
1964 MagickExport MagickSizeType GetImageExtent(const Image *image)
1970 id = GetOpenMPThreadId();
1972 assert(image != (Image *) NULL);
1973 assert(image->signature == MagickSignature);
1974 if (image->debug != MagickFalse)
1975 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1976 assert(image->cache != (Cache) NULL);
1977 cache_info=(CacheInfo *) image->cache;
1978 assert(cache_info->signature == MagickSignature);
1979 assert(id < (int) cache_info->number_threads);
1980 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1984 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1988 + G e t I m a g e P i x e l C a c h e %
1992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1994 % GetImagePixelCache() ensures that there is only a single reference to the
1995 % pixel cache to be modified, updating the provided cache pointer to point to
1996 % a clone of the original pixel cache if necessary.
1998 % The format of the GetImagePixelCache method is:
2000 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2001 % ExceptionInfo *exception)
2003 % A description of each parameter follows:
2005 % o image: the image.
2007 % o clone: any value other than MagickFalse clones the cache pixels.
2009 % o exception: return any errors or warnings in this structure.
2012 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2018 Does the image match the pixel cache morphology?
2020 cache_info=(CacheInfo *) image->cache;
2021 if ((image->storage_class != cache_info->storage_class) ||
2022 (image->colorspace != cache_info->colorspace) ||
2023 (image->columns != cache_info->columns) ||
2024 (image->rows != cache_info->rows) ||
2025 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2026 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2027 return(MagickFalse);
2031 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2032 ExceptionInfo *exception)
2041 static MagickSizeType
2050 LockSemaphoreInfo(image->semaphore);
2051 if (cpu_throttle == 0)
2057 Set CPU throttle in milleseconds.
2059 cpu_throttle=MagickResourceInfinity;
2060 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2061 if (limit == (char *) NULL)
2062 limit=GetPolicyValue("throttle");
2063 if (limit != (char *) NULL)
2065 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2066 limit=DestroyString(limit);
2069 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2070 MagickDelay(cpu_throttle);
2071 if (time_limit == 0)
2074 Set the exire time in seconds.
2076 time_limit=GetMagickResourceLimit(TimeResource);
2077 cache_genesis=time((time_t *) NULL);
2079 if ((time_limit != MagickResourceInfinity) &&
2080 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
2081 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2082 assert(image->cache != (Cache) NULL);
2083 cache_info=(CacheInfo *) image->cache;
2084 destroy=MagickFalse;
2085 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2087 LockSemaphoreInfo(cache_info->semaphore);
2088 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2099 clone_image=(*image);
2100 clone_image.semaphore=AllocateSemaphoreInfo();
2101 clone_image.reference_count=1;
2102 clone_image.cache=ClonePixelCache(cache_info);
2103 clone_info=(CacheInfo *) clone_image.cache;
2104 status=OpenPixelCache(&clone_image,IOMode,exception);
2105 if (status != MagickFalse)
2107 if (clone != MagickFalse)
2108 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2109 if (status != MagickFalse)
2112 image->cache=clone_image.cache;
2115 DestroySemaphoreInfo(&clone_image.semaphore);
2117 UnlockSemaphoreInfo(cache_info->semaphore);
2119 if (destroy != MagickFalse)
2120 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2121 if (status != MagickFalse)
2124 Ensure the image matches the pixel cache morphology.
2126 image->taint=MagickTrue;
2127 image->type=UndefinedType;
2128 if (image->colorspace == GRAYColorspace)
2129 image->colorspace=RGBColorspace;
2130 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2131 status=OpenPixelCache(image,IOMode,exception);
2133 UnlockSemaphoreInfo(image->semaphore);
2134 if (status == MagickFalse)
2135 return((Cache) NULL);
2136 return(image->cache);
2140 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2144 % G e t O n e A u t h e n t i c P i x e l %
2148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2150 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2151 % location. The image background color is returned if an error occurs.
2153 % The format of the GetOneAuthenticPixel() method is:
2155 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2156 % const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2158 % A description of each parameter follows:
2160 % o image: the image.
2162 % o x,y: These values define the location of the pixel to return.
2164 % o pixel: return a pixel at the specified (x,y) location.
2166 % o exception: return any errors or warnings in this structure.
2169 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2170 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2178 assert(image != (Image *) NULL);
2179 assert(image->signature == MagickSignature);
2180 assert(image->cache != (Cache) NULL);
2181 cache_info=(CacheInfo *) image->cache;
2182 assert(cache_info->signature == MagickSignature);
2183 *pixel=image->background_color;
2184 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2185 (GetOneAuthenticPixelFromHandler) NULL)
2186 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2188 *pixel=image->background_color;
2189 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2190 if (pixels == (PixelPacket *) NULL)
2191 return(MagickFalse);
2197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2201 + 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 %
2205 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2207 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2208 % location. The image background color is returned if an error occurs.
2210 % The format of the GetOneAuthenticPixelFromCache() method is:
2212 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2213 % const ssize_t x,const ssize_t y,PixelPacket *pixel,
2214 % ExceptionInfo *exception)
2216 % A description of each parameter follows:
2218 % o image: the image.
2220 % o x,y: These values define the location of the pixel to return.
2222 % o pixel: return a pixel at the specified (x,y) location.
2224 % o exception: return any errors or warnings in this structure.
2227 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2228 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2234 id = GetOpenMPThreadId();
2239 assert(image != (const Image *) NULL);
2240 assert(image->signature == MagickSignature);
2241 assert(image->cache != (Cache) NULL);
2242 cache_info=(CacheInfo *) image->cache;
2243 assert(cache_info->signature == MagickSignature);
2244 *pixel=image->background_color;
2245 assert(id < (int) cache_info->number_threads);
2246 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2247 cache_info->nexus_info[id],exception);
2248 if (pixels == (PixelPacket *) NULL)
2249 return(MagickFalse);
2255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2259 % G e t O n e V i r t u a l M a g i c k P i x e l %
2263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2265 % GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2266 % location. The image background color is returned if an error occurs. If
2267 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2269 % The format of the GetOneVirtualMagickPixel() method is:
2271 % MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2272 % const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2273 % ExceptionInfo exception)
2275 % A description of each parameter follows:
2277 % o image: the image.
2279 % o x,y: these values define the location of the pixel to return.
2281 % o pixel: return a pixel at the specified (x,y) location.
2283 % o exception: return any errors or warnings in this structure.
2286 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2287 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2288 ExceptionInfo *exception)
2294 id = GetOpenMPThreadId();
2296 register const IndexPacket
2299 register const PixelPacket
2302 assert(image != (const 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 GetMagickPixelPacket(image,pixel);
2308 assert(id < (int) cache_info->number_threads);
2309 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2310 1UL,1UL,cache_info->nexus_info[id],exception);
2311 if (pixels == (const PixelPacket *) NULL)
2312 return(MagickFalse);
2313 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
2314 SetMagickPixelPacket(image,pixels,indexes,pixel);
2319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2323 % G e t O n e V i r t u a l M e t h o d P i x e l %
2327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2329 % GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2330 % location as defined by specified pixel method. The image background color
2331 % is returned if an error occurs. If you plan to modify the pixel, use
2332 % GetOneAuthenticPixel() instead.
2334 % The format of the GetOneVirtualMethodPixel() method is:
2336 % MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2337 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2338 % const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
2340 % A description of each parameter follows:
2342 % o image: the image.
2344 % o virtual_pixel_method: the virtual pixel method.
2346 % o x,y: These values define the location of the pixel to return.
2348 % o pixel: return a pixel at the specified (x,y) location.
2350 % o exception: return any errors or warnings in this structure.
2353 MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2354 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2355 PixelPacket *pixel,ExceptionInfo *exception)
2361 id = GetOpenMPThreadId();
2366 assert(image != (const Image *) NULL);
2367 assert(image->signature == MagickSignature);
2368 assert(image->cache != (Cache) NULL);
2369 cache_info=(CacheInfo *) image->cache;
2370 assert(cache_info->signature == MagickSignature);
2371 *pixel=image->background_color;
2372 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2373 (GetOneVirtualPixelFromHandler) NULL)
2374 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2375 virtual_pixel_method,x,y,pixel,exception));
2376 *pixel=image->background_color;
2377 assert(id < (int) cache_info->number_threads);
2378 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2379 cache_info->nexus_info[id],exception);
2380 if (pixels == (const PixelPacket *) NULL)
2381 return(MagickFalse);
2387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2391 % G e t O n e V i r t u a l P i x e l %
2395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2397 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2398 % (x,y) location. The image background color is returned if an error occurs.
2399 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2401 % The format of the GetOneVirtualPixel() method is:
2403 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2404 % const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
2406 % A description of each parameter follows:
2408 % o image: the image.
2410 % o x,y: These values define the location of the pixel to return.
2412 % o pixel: return a pixel at the specified (x,y) location.
2414 % o exception: return any errors or warnings in this structure.
2417 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2418 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2424 id = GetOpenMPThreadId();
2429 assert(image != (const Image *) NULL);
2430 assert(image->signature == MagickSignature);
2431 assert(image->cache != (Cache) NULL);
2432 cache_info=(CacheInfo *) image->cache;
2433 assert(cache_info->signature == MagickSignature);
2434 *pixel=image->background_color;
2435 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2436 (GetOneVirtualPixelFromHandler) NULL)
2437 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2438 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2439 assert(id < (int) cache_info->number_threads);
2440 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2441 1UL,1UL,cache_info->nexus_info[id],exception);
2442 if (pixels == (const PixelPacket *) NULL)
2443 return(MagickFalse);
2449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2453 + 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 %
2457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2459 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2460 % specified (x,y) location. The image background color is returned if an
2463 % The format of the GetOneVirtualPixelFromCache() method is:
2465 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2466 % const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
2467 % PixelPacket *pixel,ExceptionInfo *exception)
2469 % A description of each parameter follows:
2471 % o image: the image.
2473 % o virtual_pixel_method: the virtual pixel method.
2475 % o x,y: These values define the location of the pixel to return.
2477 % o pixel: return a pixel at the specified (x,y) location.
2479 % o exception: return any errors or warnings in this structure.
2482 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2483 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2484 PixelPacket *pixel,ExceptionInfo *exception)
2490 id = GetOpenMPThreadId();
2495 *pixel=image->background_color;
2496 cache_info=(CacheInfo *) image->cache;
2497 assert(id < (int) cache_info->number_threads);
2498 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2499 cache_info->nexus_info[id],exception);
2500 if (pixels == (const PixelPacket *) NULL)
2501 return(MagickFalse);
2507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2511 + G e t P i x e l C a c h e C o l o r s p a c e %
2515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2517 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2519 % The format of the GetPixelCacheColorspace() method is:
2521 % Colorspace GetPixelCacheColorspace(Cache cache)
2523 % A description of each parameter follows:
2525 % o cache: the pixel cache.
2528 MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2533 assert(cache != (Cache) NULL);
2534 cache_info=(CacheInfo *) cache;
2535 assert(cache_info->signature == MagickSignature);
2536 if (cache_info->debug != MagickFalse)
2537 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2538 cache_info->filename);
2539 return(cache_info->colorspace);
2543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2547 + G e t P i x e l C a c h e M e t h o d s %
2551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2553 % GetPixelCacheMethods() initializes the CacheMethods structure.
2555 % The format of the GetPixelCacheMethods() method is:
2557 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2559 % A description of each parameter follows:
2561 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2564 MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2566 assert(cache_methods != (CacheMethods *) NULL);
2567 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2568 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2569 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2570 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2571 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2572 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2573 cache_methods->get_authentic_indexes_from_handler=
2574 GetAuthenticIndexesFromCache;
2575 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2576 cache_methods->get_one_authentic_pixel_from_handler=
2577 GetOneAuthenticPixelFromCache;
2578 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2579 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2580 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2584 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2588 + G e t P i x e l C a c h e N e x u s E x t e n t %
2592 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2594 % GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2595 % the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2597 % The format of the GetPixelCacheNexusExtent() method is:
2599 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2600 % NexusInfo *nexus_info)
2602 % A description of each parameter follows:
2604 % o nexus_info: the nexus info.
2607 MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2608 NexusInfo *nexus_info)
2616 assert(cache != (Cache) NULL);
2617 cache_info=(CacheInfo *) cache;
2618 assert(cache_info->signature == MagickSignature);
2619 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2621 return((MagickSizeType) cache_info->columns*cache_info->rows);
2626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2630 + 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 %
2634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2636 % GetPixelCacheNexusIndexes() returns the indexes associated with the
2637 % specified cache nexus.
2639 % The format of the GetPixelCacheNexusIndexes() method is:
2641 % IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2642 % NexusInfo *nexus_info)
2644 % A description of each parameter follows:
2646 % o cache: the pixel cache.
2648 % o nexus_info: the cache nexus to return the colormap indexes.
2651 MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2652 NexusInfo *nexus_info)
2657 if (cache == (Cache) NULL)
2658 return((IndexPacket *) NULL);
2659 cache_info=(CacheInfo *) cache;
2660 assert(cache_info->signature == MagickSignature);
2661 if (cache_info->storage_class == UndefinedClass)
2662 return((IndexPacket *) NULL);
2663 return(nexus_info->indexes);
2667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2671 + G e t P i x e l C a c h e N e x u s P i x e l s %
2675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2677 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2680 % The format of the GetPixelCacheNexusPixels() method is:
2682 % PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2683 % NexusInfo *nexus_info)
2685 % A description of each parameter follows:
2687 % o cache: the pixel cache.
2689 % o nexus_info: the cache nexus to return the pixels.
2692 MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2693 NexusInfo *nexus_info)
2698 if (cache == (Cache) NULL)
2699 return((PixelPacket *) NULL);
2700 cache_info=(CacheInfo *) cache;
2701 assert(cache_info->signature == MagickSignature);
2702 if (cache_info->storage_class == UndefinedClass)
2703 return((PixelPacket *) NULL);
2704 return(nexus_info->pixels);
2708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2712 + G e t P i x e l C a c h e P i x e l s %
2716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2718 % GetPixelCachePixels() returns the pixels associated with the specified image.
2720 % The format of the GetPixelCachePixels() method is:
2722 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2723 % ExceptionInfo *exception)
2725 % A description of each parameter follows:
2727 % o image: the image.
2729 % o length: the pixel cache length.
2731 % o exception: return any errors or warnings in this structure.
2734 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2735 ExceptionInfo *exception)
2740 assert(image != (const Image *) NULL);
2741 assert(image->signature == MagickSignature);
2742 assert(image->cache != (Cache) NULL);
2743 cache_info=(CacheInfo *) image->cache;
2744 assert(cache_info->signature == MagickSignature);
2746 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2747 return((void *) NULL);
2748 *length=cache_info->length;
2749 return((void *) cache_info->pixels);
2753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757 + 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 %
2761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2763 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2765 % The format of the GetPixelCacheStorageClass() method is:
2767 % ClassType GetPixelCacheStorageClass(Cache cache)
2769 % A description of each parameter follows:
2771 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2773 % o cache: the pixel cache.
2776 MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2781 assert(cache != (Cache) NULL);
2782 cache_info=(CacheInfo *) cache;
2783 assert(cache_info->signature == MagickSignature);
2784 if (cache_info->debug != MagickFalse)
2785 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2786 cache_info->filename);
2787 return(cache_info->storage_class);
2791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2795 + G e t P i x e l C a c h e T i l e S i z e %
2799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2801 % GetPixelCacheTileSize() returns the pixel cache tile size.
2803 % The format of the GetPixelCacheTileSize() method is:
2805 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2808 % A description of each parameter follows:
2810 % o image: the image.
2812 % o width: the optimize cache tile width in pixels.
2814 % o height: the optimize cache tile height in pixels.
2817 MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2823 assert(image != (Image *) NULL);
2824 assert(image->signature == MagickSignature);
2825 if (image->debug != MagickFalse)
2826 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2827 assert(image->cache != (Cache) NULL);
2828 cache_info=(CacheInfo *) image->cache;
2829 assert(cache_info->signature == MagickSignature);
2830 *width=2048UL/sizeof(PixelPacket);
2831 if (GetPixelCacheType(image) == DiskCache)
2832 *width=8192UL/sizeof(PixelPacket);
2837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2841 + G e t P i x e l C a c h e T y p e %
2845 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2847 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2849 % The format of the GetPixelCacheType() method is:
2851 % CacheType GetPixelCacheType(const Image *image)
2853 % A description of each parameter follows:
2855 % o image: the image.
2858 MagickExport CacheType GetPixelCacheType(const Image *image)
2863 assert(image != (Image *) NULL);
2864 assert(image->signature == MagickSignature);
2865 assert(image->cache != (Cache) NULL);
2866 cache_info=(CacheInfo *) image->cache;
2867 assert(cache_info->signature == MagickSignature);
2868 return(cache_info->type);
2872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2876 + 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 %
2880 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2882 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2883 % pixel cache. A virtual pixel is any pixel access that is outside the
2884 % boundaries of the image cache.
2886 % The format of the GetPixelCacheVirtualMethod() method is:
2888 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2890 % A description of each parameter follows:
2892 % o image: the image.
2895 MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2900 assert(image != (Image *) NULL);
2901 assert(image->signature == MagickSignature);
2902 assert(image->cache != (Cache) NULL);
2903 cache_info=(CacheInfo *) image->cache;
2904 assert(cache_info->signature == MagickSignature);
2905 return(cache_info->virtual_pixel_method);
2909 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2913 + 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 %
2917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2919 % GetVirtualIndexesFromCache() returns the indexes associated with the last
2920 % call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2922 % The format of the GetVirtualIndexesFromCache() method is:
2924 % IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2926 % A description of each parameter follows:
2928 % o image: the image.
2931 static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2937 id = GetOpenMPThreadId();
2939 cache_info=(CacheInfo *) image->cache;
2940 assert(id < (int) cache_info->number_threads);
2941 return(GetVirtualIndexesFromNexus(image->cache,cache_info->nexus_info[id]));
2945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2949 + 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 %
2953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2955 % GetVirtualIndexesFromNexus() returns the indexes associated with the
2956 % specified cache nexus.
2958 % The format of the GetVirtualIndexesFromNexus() method is:
2960 % const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2961 % NexusInfo *nexus_info)
2963 % A description of each parameter follows:
2965 % o cache: the pixel cache.
2967 % o nexus_info: the cache nexus to return the colormap indexes.
2970 MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2971 NexusInfo *nexus_info)
2976 if (cache == (Cache) NULL)
2977 return((IndexPacket *) NULL);
2978 cache_info=(CacheInfo *) cache;
2979 assert(cache_info->signature == MagickSignature);
2980 if (cache_info->storage_class == UndefinedClass)
2981 return((IndexPacket *) NULL);
2982 return(nexus_info->indexes);
2986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2990 % G e t V i r t u a l I n d e x Q u e u e %
2994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2996 % GetVirtualIndexQueue() returns the virtual black channel or the
2997 % colormap indexes associated with the last call to QueueAuthenticPixels() or
2998 % GetVirtualPixels(). NULL is returned if the black channel or colormap
2999 % indexes are not available.
3001 % The format of the GetVirtualIndexQueue() method is:
3003 % const IndexPacket *GetVirtualIndexQueue(const Image *image)
3005 % A description of each parameter follows:
3007 % o image: the image.
3010 MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3016 id = GetOpenMPThreadId();
3018 assert(image != (const Image *) NULL);
3019 assert(image->signature == MagickSignature);
3020 assert(image->cache != (Cache) NULL);
3021 cache_info=(CacheInfo *) image->cache;
3022 assert(cache_info->signature == MagickSignature);
3023 if (cache_info->methods.get_virtual_indexes_from_handler !=
3024 (GetVirtualIndexesFromHandler) NULL)
3025 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3026 assert(id < (int) cache_info->number_threads);
3027 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
3031 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3035 + G e t V i r t u a l P i x e l s F r o m N e x u s %
3039 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3041 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3042 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3043 % is returned if the pixels are transferred, otherwise a NULL is returned.
3045 % The format of the GetVirtualPixelsFromNexus() method is:
3047 % PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3048 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3049 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
3050 % ExceptionInfo *exception)
3052 % A description of each parameter follows:
3054 % o image: the image.
3056 % o virtual_pixel_method: the virtual pixel method.
3058 % o x,y,columns,rows: These values define the perimeter of a region of
3061 % o nexus_info: the cache nexus to acquire.
3063 % o exception: return any errors or warnings in this structure.
3070 0, 48, 12, 60, 3, 51, 15, 63,
3071 32, 16, 44, 28, 35, 19, 47, 31,
3072 8, 56, 4, 52, 11, 59, 7, 55,
3073 40, 24, 36, 20, 43, 27, 39, 23,
3074 2, 50, 14, 62, 1, 49, 13, 61,
3075 34, 18, 46, 30, 33, 17, 45, 29,
3076 10, 58, 6, 54, 9, 57, 5, 53,
3077 42, 26, 38, 22, 41, 25, 37, 21
3080 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3085 index=x+DitherMatrix[x & 0x07]-32L;
3088 if (index >= (ssize_t) columns)
3089 return((ssize_t) columns-1L);
3093 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3098 index=y+DitherMatrix[y & 0x07]-32L;
3101 if (index >= (ssize_t) rows)
3102 return((ssize_t) rows-1L);
3106 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3110 if (x >= (ssize_t) columns)
3111 return((ssize_t) (columns-1));
3115 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3119 if (y >= (ssize_t) rows)
3120 return((ssize_t) (rows-1));
3124 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3126 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3129 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3131 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3135 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3136 returns not only the quotient (tile the offset falls in) but also the positive
3137 remainer within that tile such that 0 <= remainder < extent. This method is
3138 essentially a ldiv() using a floored modulo division rather than the normal
3139 default truncated modulo division.
3141 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3142 const size_t extent)
3147 modulo.quotient=offset/(ssize_t) extent;
3150 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3154 MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3155 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3156 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3157 ExceptionInfo *exception)
3182 register const IndexPacket
3183 *restrict virtual_indexes;
3185 register const PixelPacket
3188 register IndexPacket
3191 register PixelPacket
3201 cache_info=(CacheInfo *) image->cache;
3202 if (cache_info->type == UndefinedCache)
3203 return((const PixelPacket *) NULL);
3206 region.width=columns;
3208 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3209 if (pixels == (PixelPacket *) NULL)
3210 return((const PixelPacket *) NULL);
3211 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3212 nexus_info->region.x;
3213 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3214 nexus_info->region.width-1L;
3215 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3216 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3217 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3218 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3224 Pixel request is inside cache extents.
3226 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3228 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3229 if (status == MagickFalse)
3230 return((const PixelPacket *) NULL);
3231 if ((cache_info->storage_class == PseudoClass) ||
3232 (cache_info->colorspace == CMYKColorspace))
3234 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3235 if (status == MagickFalse)
3236 return((const PixelPacket *) NULL);
3241 Pixel request is outside cache extents.
3244 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3245 virtual_nexus=AcquirePixelCacheNexus(1);
3246 if (virtual_nexus == (NexusInfo **) NULL)
3248 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3249 "UnableToGetCacheNexus","`%s'",image->filename);
3250 return((const PixelPacket *) NULL);
3252 switch (virtual_pixel_method)
3254 case BlackVirtualPixelMethod:
3256 SetRedPixelComponent(&virtual_pixel,0);
3257 SetGreenPixelComponent(&virtual_pixel,0);
3258 SetBluePixelComponent(&virtual_pixel,0);
3259 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3262 case GrayVirtualPixelMethod:
3264 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3265 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3266 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3267 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3270 case TransparentVirtualPixelMethod:
3272 SetRedPixelComponent(&virtual_pixel,0);
3273 SetGreenPixelComponent(&virtual_pixel,0);
3274 SetBluePixelComponent(&virtual_pixel,0);
3275 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
3278 case MaskVirtualPixelMethod:
3279 case WhiteVirtualPixelMethod:
3281 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3282 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3283 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3284 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3289 virtual_pixel=image->background_color;
3294 for (v=0; v < (ssize_t) rows; v++)
3296 for (u=0; u < (ssize_t) columns; u+=length)
3298 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3299 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3300 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3308 Transfer a single pixel.
3310 length=(MagickSizeType) 1;
3311 switch (virtual_pixel_method)
3313 case BackgroundVirtualPixelMethod:
3314 case ConstantVirtualPixelMethod:
3315 case BlackVirtualPixelMethod:
3316 case GrayVirtualPixelMethod:
3317 case TransparentVirtualPixelMethod:
3318 case MaskVirtualPixelMethod:
3319 case WhiteVirtualPixelMethod:
3322 virtual_indexes=(&virtual_index);
3325 case EdgeVirtualPixelMethod:
3328 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3329 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3330 1UL,1UL,virtual_nexus[0],exception);
3331 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3335 case RandomVirtualPixelMethod:
3337 if (cache_info->random_info == (RandomInfo *) NULL)
3338 cache_info->random_info=AcquireRandomInfo();
3339 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3340 RandomX(cache_info->random_info,cache_info->columns),
3341 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3342 virtual_nexus[0],exception);
3343 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3347 case DitherVirtualPixelMethod:
3349 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3350 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3351 1UL,1UL,virtual_nexus[0],exception);
3352 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3356 case TileVirtualPixelMethod:
3358 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3359 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3360 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3361 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3363 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3367 case MirrorVirtualPixelMethod:
3369 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3370 if ((x_modulo.quotient & 0x01) == 1L)
3371 x_modulo.remainder=(ssize_t) cache_info->columns-
3372 x_modulo.remainder-1L;
3373 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3374 if ((y_modulo.quotient & 0x01) == 1L)
3375 y_modulo.remainder=(ssize_t) cache_info->rows-
3376 y_modulo.remainder-1L;
3377 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3378 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3380 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3384 case CheckerTileVirtualPixelMethod:
3386 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3387 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3388 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3391 virtual_indexes=(&virtual_index);
3394 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3395 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3397 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3401 case HorizontalTileVirtualPixelMethod:
3403 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3406 virtual_indexes=(&virtual_index);
3409 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3410 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3411 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3412 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3414 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3418 case VerticalTileVirtualPixelMethod:
3420 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3423 virtual_indexes=(&virtual_index);
3426 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3427 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3428 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3429 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus[0],
3431 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3435 case HorizontalTileEdgeVirtualPixelMethod:
3437 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3438 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3439 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3440 virtual_nexus[0],exception);
3441 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3445 case VerticalTileEdgeVirtualPixelMethod:
3447 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3448 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3449 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3450 virtual_nexus[0],exception);
3451 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3456 if (p == (const PixelPacket *) NULL)
3459 if ((indexes != (IndexPacket *) NULL) &&
3460 (virtual_indexes != (const IndexPacket *) NULL))
3461 *indexes++=(*virtual_indexes);
3465 Transfer a run of pixels.
3467 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3468 (size_t) length,1UL,virtual_nexus[0],exception);
3469 if (p == (const PixelPacket *) NULL)
3471 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus[0]);
3472 (void) memcpy(q,p,(size_t) length*sizeof(*p));
3474 if ((indexes != (IndexPacket *) NULL) &&
3475 (virtual_indexes != (const IndexPacket *) NULL))
3477 (void) memcpy(indexes,virtual_indexes,(size_t) length*
3478 sizeof(*virtual_indexes));
3483 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3492 + G e t V i r t u a l P i x e l C a c h e %
3496 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3498 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3499 % cache as defined by the geometry parameters. A pointer to the pixels
3500 % is returned if the pixels are transferred, otherwise a NULL is returned.
3502 % The format of the GetVirtualPixelCache() method is:
3504 % const PixelPacket *GetVirtualPixelCache(const Image *image,
3505 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3506 % const ssize_t y,const size_t columns,const size_t rows,
3507 % ExceptionInfo *exception)
3509 % A description of each parameter follows:
3511 % o image: the image.
3513 % o virtual_pixel_method: the virtual pixel method.
3515 % o x,y,columns,rows: These values define the perimeter of a region of
3518 % o exception: return any errors or warnings in this structure.
3521 static const PixelPacket *GetVirtualPixelCache(const Image *image,
3522 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3523 const size_t columns,const size_t rows,ExceptionInfo *exception)
3529 id = GetOpenMPThreadId();
3531 cache_info=(CacheInfo *) image->cache;
3532 assert(id < (int) cache_info->number_threads);
3533 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3534 cache_info->nexus_info[id],exception));
3538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3542 % G e t V i r t u a l P i x e l Q u e u e %
3546 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3548 % GetVirtualPixelQueue() returns the virtual pixels associated with the
3549 % last call to QueueAuthenticPixels() or GetVirtualPixels().
3551 % The format of the GetVirtualPixelQueue() method is:
3553 % const PixelPacket *GetVirtualPixelQueue(const Image image)
3555 % A description of each parameter follows:
3557 % o image: the image.
3560 MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3566 id = GetOpenMPThreadId();
3568 assert(image != (const Image *) NULL);
3569 assert(image->signature == MagickSignature);
3570 assert(image->cache != (Cache) NULL);
3571 cache_info=(CacheInfo *) image->cache;
3572 assert(cache_info->signature == MagickSignature);
3573 if (cache_info->methods.get_virtual_pixels_handler !=
3574 (GetVirtualPixelsHandler) NULL)
3575 return(cache_info->methods.get_virtual_pixels_handler(image));
3576 assert(id < (int) cache_info->number_threads);
3577 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3585 % G e t V i r t u a l P i x e l s %
3589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3591 % GetVirtualPixels() returns an immutable pixel region. If the
3592 % region is successfully accessed, a pointer to it is returned, otherwise
3593 % NULL is returned. The returned pointer may point to a temporary working
3594 % copy of the pixels or it may point to the original pixels in memory.
3595 % Performance is maximized if the selected region is part of one row, or one
3596 % or more full rows, since there is opportunity to access the pixels in-place
3597 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3598 % returned pointer must *never* be deallocated by the user.
3600 % Pixels accessed via the returned pointer represent a simple array of type
3601 % PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3602 % call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3603 % the black color component or to obtain the colormap indexes (of type
3604 % IndexPacket) corresponding to the region.
3606 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3608 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3609 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3610 % GetCacheViewAuthenticPixels() instead.
3612 % The format of the GetVirtualPixels() method is:
3614 % const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3615 % const ssize_t y,const size_t columns,const size_t rows,
3616 % ExceptionInfo *exception)
3618 % A description of each parameter follows:
3620 % o image: the image.
3622 % o x,y,columns,rows: These values define the perimeter of a region of
3625 % o exception: return any errors or warnings in this structure.
3628 MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3629 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3630 ExceptionInfo *exception)
3636 id = GetOpenMPThreadId();
3638 assert(image != (const Image *) NULL);
3639 assert(image->signature == MagickSignature);
3640 assert(image->cache != (Cache) NULL);
3641 cache_info=(CacheInfo *) image->cache;
3642 assert(cache_info->signature == MagickSignature);
3643 if (cache_info->methods.get_virtual_pixel_handler !=
3644 (GetVirtualPixelHandler) NULL)
3645 return(cache_info->methods.get_virtual_pixel_handler(image,
3646 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3647 assert(id < (int) cache_info->number_threads);
3648 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3649 columns,rows,cache_info->nexus_info[id],exception));
3653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3657 + 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 %
3661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3663 % GetVirtualPixelsCache() returns the pixels associated with the last call
3664 % to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3666 % The format of the GetVirtualPixelsCache() method is:
3668 % PixelPacket *GetVirtualPixelsCache(const Image *image)
3670 % A description of each parameter follows:
3672 % o image: the image.
3675 static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3681 id = GetOpenMPThreadId();
3683 cache_info=(CacheInfo *) image->cache;
3684 assert(id < (int) cache_info->number_threads);
3685 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3689 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3693 + G e t V i r t u a l P i x e l s N e x u s %
3697 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3699 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3702 % The format of the GetVirtualPixelsNexus() method is:
3704 % const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3705 % NexusInfo *nexus_info)
3707 % A description of each parameter follows:
3709 % o cache: the pixel cache.
3711 % o nexus_info: the cache nexus to return the colormap pixels.
3714 MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3715 NexusInfo *nexus_info)
3720 if (cache == (Cache) NULL)
3721 return((PixelPacket *) NULL);
3722 cache_info=(CacheInfo *) cache;
3723 assert(cache_info->signature == MagickSignature);
3724 if (cache_info->storage_class == UndefinedClass)
3725 return((PixelPacket *) NULL);
3726 return((const PixelPacket *) nexus_info->pixels);
3730 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3734 + M a s k P i x e l C a c h e N e x u s %
3738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3740 % MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3741 % The method returns MagickTrue if the pixel region is masked, otherwise
3744 % The format of the MaskPixelCacheNexus() method is:
3746 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3747 % NexusInfo *nexus_info,ExceptionInfo *exception)
3749 % A description of each parameter follows:
3751 % o image: the image.
3753 % o nexus_info: the cache nexus to clip.
3755 % o exception: return any errors or warnings in this structure.
3759 static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3760 const MagickRealType alpha,const MagickPixelPacket *q,
3761 const MagickRealType beta,MagickPixelPacket *composite)
3766 if (alpha == TransparentOpacity)
3771 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3772 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3773 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3774 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3775 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3776 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3777 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3780 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3781 ExceptionInfo *exception)
3797 register const PixelPacket
3800 register IndexPacket
3801 *restrict nexus_indexes,
3804 register PixelPacket
3814 if (image->debug != MagickFalse)
3815 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3816 if (image->mask == (Image *) NULL)
3817 return(MagickFalse);
3818 cache_info=(CacheInfo *) image->cache;
3819 if (cache_info == (Cache) NULL)
3820 return(MagickFalse);
3821 image_nexus=AcquirePixelCacheNexus(1);
3822 clip_nexus=AcquirePixelCacheNexus(1);
3823 if ((image_nexus == (NexusInfo **) NULL) ||
3824 (clip_nexus == (NexusInfo **) NULL))
3825 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3826 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3827 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3828 image_nexus[0],exception);
3829 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3830 q=nexus_info->pixels;
3831 nexus_indexes=nexus_info->indexes;
3832 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3833 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3834 nexus_info->region.height,clip_nexus[0],&image->exception);
3835 GetMagickPixelPacket(image,&alpha);
3836 GetMagickPixelPacket(image,&beta);
3837 number_pixels=(MagickSizeType) nexus_info->region.width*
3838 nexus_info->region.height;
3839 for (i=0; i < (ssize_t) number_pixels; i++)
3841 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3843 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3844 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3845 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3846 &alpha,alpha.opacity,&beta);
3847 q->red=ClampToQuantum(beta.red);
3848 q->green=ClampToQuantum(beta.green);
3849 q->blue=ClampToQuantum(beta.blue);
3850 q->opacity=ClampToQuantum(beta.opacity);
3851 if (cache_info->active_index_channel != MagickFalse)
3852 nexus_indexes[i]=indexes[i];
3857 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3858 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3859 if (i < (ssize_t) number_pixels)
3860 return(MagickFalse);
3865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3869 + O p e n P i x e l C a c h e %
3873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3875 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3876 % dimensions, allocating space for the image pixels and optionally the
3877 % colormap indexes, and memory mapping the cache if it is disk based. The
3878 % cache nexus array is initialized as well.
3880 % The format of the OpenPixelCache() method is:
3882 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3883 % ExceptionInfo *exception)
3885 % A description of each parameter follows:
3887 % o image: the image.
3889 % o mode: ReadMode, WriteMode, or IOMode.
3891 % o exception: return any errors or warnings in this structure.
3895 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3897 cache_info->mapped=MagickFalse;
3898 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3899 cache_info->length);
3900 if (cache_info->pixels == (PixelPacket *) NULL)
3902 cache_info->mapped=MagickTrue;
3903 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3904 cache_info->length);
3908 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3918 cache_info=(CacheInfo *) image->cache;
3919 if (image->debug != MagickFalse)
3922 format[MaxTextExtent],
3923 message[MaxTextExtent];
3925 (void) FormatMagickSize(length,MagickFalse,format);
3926 (void) FormatMagickString(message,MaxTextExtent,
3927 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
3928 cache_info->cache_filename,cache_info->file,format);
3929 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3931 if (length != (MagickSizeType) ((MagickOffsetType) length))
3932 return(MagickFalse);
3933 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3935 return(MagickFalse);
3936 if ((MagickSizeType) extent >= length)
3938 offset=(MagickOffsetType) length-1;
3939 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3940 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3943 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3944 ExceptionInfo *exception)
3947 format[MaxTextExtent],
3948 message[MaxTextExtent];
3965 if (image->debug != MagickFalse)
3966 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3967 if ((image->columns == 0) || (image->rows == 0))
3968 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3969 cache_info=(CacheInfo *) image->cache;
3970 source_info=(*cache_info);
3971 source_info.file=(-1);
3972 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
3973 image->filename,(double) GetImageIndexInList(image));
3974 cache_info->mode=mode;
3975 cache_info->rows=image->rows;
3976 cache_info->columns=image->columns;
3977 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3978 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
3979 if (image->ping != MagickFalse)
3981 cache_info->storage_class=image->storage_class;
3982 cache_info->colorspace=image->colorspace;
3983 cache_info->type=PingCache;
3984 cache_info->pixels=(PixelPacket *) NULL;
3985 cache_info->indexes=(IndexPacket *) NULL;
3986 cache_info->length=0;
3989 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3990 packet_size=sizeof(PixelPacket);
3991 if (cache_info->active_index_channel != MagickFalse)
3992 packet_size+=sizeof(IndexPacket);
3993 length=number_pixels*packet_size;
3994 columns=(size_t) (length/cache_info->rows/packet_size);
3995 if (cache_info->columns != columns)
3996 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
3998 cache_info->length=length;
3999 status=AcquireMagickResource(AreaResource,cache_info->length);
4000 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4001 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4003 status=AcquireMagickResource(MemoryResource,cache_info->length);
4004 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4005 (cache_info->type == MemoryCache))
4007 AllocatePixelCachePixels(cache_info);
4008 if (cache_info->pixels == (PixelPacket *) NULL)
4009 cache_info->pixels=source_info.pixels;
4013 Create memory pixel cache.
4015 if (image->debug != MagickFalse)
4017 (void) FormatMagickSize(cache_info->length,MagickTrue,
4019 (void) FormatMagickString(message,MaxTextExtent,
4020 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
4021 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4022 (double) cache_info->columns,(double) cache_info->rows,
4024 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4027 cache_info->storage_class=image->storage_class;
4028 cache_info->colorspace=image->colorspace;
4029 cache_info->type=MemoryCache;
4030 cache_info->indexes=(IndexPacket *) NULL;
4031 if (cache_info->active_index_channel != MagickFalse)
4032 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4034 if (source_info.storage_class != UndefinedClass)
4036 status|=ClonePixelCachePixels(cache_info,&source_info,
4038 RelinquishPixelCachePixels(&source_info);
4043 RelinquishMagickResource(MemoryResource,cache_info->length);
4046 Create pixel cache on disk.
4048 status=AcquireMagickResource(DiskResource,cache_info->length);
4049 if (status == MagickFalse)
4051 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4052 "CacheResourcesExhausted","`%s'",image->filename);
4053 return(MagickFalse);
4055 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4057 RelinquishMagickResource(DiskResource,cache_info->length);
4058 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4060 return(MagickFalse);
4062 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4063 cache_info->length);
4064 if (status == MagickFalse)
4066 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4068 return(MagickFalse);
4070 cache_info->storage_class=image->storage_class;
4071 cache_info->colorspace=image->colorspace;
4072 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4073 status=AcquireMagickResource(AreaResource,cache_info->length);
4074 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4075 cache_info->type=DiskCache;
4078 status=AcquireMagickResource(MapResource,cache_info->length);
4079 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4080 (cache_info->type != MemoryCache))
4081 cache_info->type=DiskCache;
4084 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4085 cache_info->offset,(size_t) cache_info->length);
4086 if (cache_info->pixels == (PixelPacket *) NULL)
4088 cache_info->pixels=source_info.pixels;
4089 cache_info->type=DiskCache;
4094 Create file-backed memory-mapped pixel cache.
4096 (void) ClosePixelCacheOnDisk(cache_info);
4097 cache_info->type=MapCache;
4098 cache_info->mapped=MagickTrue;
4099 cache_info->indexes=(IndexPacket *) NULL;
4100 if (cache_info->active_index_channel != MagickFalse)
4101 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4103 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4105 status=ClonePixelCachePixels(cache_info,&source_info,
4107 RelinquishPixelCachePixels(&source_info);
4109 if (image->debug != MagickFalse)
4111 (void) FormatMagickSize(cache_info->length,MagickTrue,
4113 (void) FormatMagickString(message,MaxTextExtent,
4114 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
4115 cache_info->filename,cache_info->cache_filename,
4116 cache_info->file,(double) cache_info->columns,(double)
4117 cache_info->rows,format);
4118 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4124 RelinquishMagickResource(MapResource,cache_info->length);
4126 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4128 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4129 RelinquishPixelCachePixels(&source_info);
4131 if (image->debug != MagickFalse)
4133 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4134 (void) FormatMagickString(message,MaxTextExtent,
4135 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4136 cache_info->cache_filename,cache_info->file,(double)
4137 cache_info->columns,(double) cache_info->rows,format);
4138 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4148 + P e r s i s t P i x e l C a c h e %
4152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4154 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4155 % persistent pixel cache is one that resides on disk and is not destroyed
4156 % when the program exits.
4158 % The format of the PersistPixelCache() method is:
4160 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4161 % const MagickBooleanType attach,MagickOffsetType *offset,
4162 % ExceptionInfo *exception)
4164 % A description of each parameter follows:
4166 % o image: the image.
4168 % o filename: the persistent pixel cache filename.
4170 % o attach: A value other than zero initializes the persistent pixel
4173 % o initialize: A value other than zero initializes the persistent pixel
4176 % o offset: the offset in the persistent cache to store pixels.
4178 % o exception: return any errors or warnings in this structure.
4181 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4182 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4183 ExceptionInfo *exception)
4198 assert(image != (Image *) NULL);
4199 assert(image->signature == MagickSignature);
4200 if (image->debug != MagickFalse)
4201 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4202 assert(image->cache != (void *) NULL);
4203 assert(filename != (const char *) NULL);
4204 assert(offset != (MagickOffsetType *) NULL);
4205 page_size=GetMagickPageSize();
4206 cache_info=(CacheInfo *) image->cache;
4207 assert(cache_info->signature == MagickSignature);
4208 if (attach != MagickFalse)
4211 Attach existing persistent pixel cache.
4213 if (image->debug != MagickFalse)
4214 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4215 "attach persistent cache");
4216 (void) CopyMagickString(cache_info->cache_filename,filename,
4218 cache_info->type=DiskCache;
4219 cache_info->offset=(*offset);
4220 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4221 return(MagickFalse);
4222 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4225 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4226 (cache_info->reference_count == 1))
4228 LockSemaphoreInfo(cache_info->semaphore);
4229 if ((cache_info->mode != ReadMode) &&
4230 (cache_info->type != MemoryCache) &&
4231 (cache_info->reference_count == 1))
4237 Usurp existing persistent pixel cache.
4239 status=rename(cache_info->cache_filename,filename);
4242 (void) CopyMagickString(cache_info->cache_filename,filename,
4244 *offset+=cache_info->length+page_size-(cache_info->length %
4246 UnlockSemaphoreInfo(cache_info->semaphore);
4247 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4248 if (image->debug != MagickFalse)
4249 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4250 "Usurp resident persistent cache");
4254 UnlockSemaphoreInfo(cache_info->semaphore);
4257 Clone persistent pixel cache.
4259 clone_image=(*image);
4260 clone_info=(CacheInfo *) clone_image.cache;
4261 image->cache=ClonePixelCache(cache_info);
4262 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4263 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4264 cache_info->type=DiskCache;
4265 cache_info->offset=(*offset);
4266 cache_info=(CacheInfo *) image->cache;
4267 status=OpenPixelCache(image,IOMode,exception);
4268 if (status != MagickFalse)
4269 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4270 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4271 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4280 + Q u e u e A u t h e n t i c N e x u s %
4284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4286 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4287 % by the region rectangle and returns a pointer to the region. This region is
4288 % subsequently transferred from the pixel cache with
4289 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4290 % pixels are transferred, otherwise a NULL is returned.
4292 % The format of the QueueAuthenticNexus() method is:
4294 % PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4295 % const ssize_t y,const size_t columns,const size_t rows,
4296 % NexusInfo *nexus_info,ExceptionInfo *exception)
4298 % A description of each parameter follows:
4300 % o image: the image.
4302 % o x,y,columns,rows: These values define the perimeter of a region of
4305 % o nexus_info: the cache nexus to set.
4307 % o exception: return any errors or warnings in this structure.
4310 MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4311 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4312 ExceptionInfo *exception)
4327 Validate pixel cache geometry.
4329 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4330 if (cache_info == (Cache) NULL)
4331 return((PixelPacket *) NULL);
4332 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4334 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4335 "NoPixelsDefinedInCache","`%s'",image->filename);
4336 return((PixelPacket *) NULL);
4338 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4339 (y >= (ssize_t) cache_info->rows))
4341 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4342 "PixelsAreNotAuthentic","`%s'",image->filename);
4343 return((PixelPacket *) NULL);
4345 offset=(MagickOffsetType) y*cache_info->columns+x;
4347 return((PixelPacket *) NULL);
4348 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4349 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4350 if ((MagickSizeType) offset >= number_pixels)
4351 return((PixelPacket *) NULL);
4357 region.width=columns;
4359 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4367 + 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 %
4371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4373 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4374 % defined by the region rectangle and returns a pointer to the region. This
4375 % region is subsequently transferred from the pixel cache with
4376 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4377 % pixels are transferred, otherwise a NULL is returned.
4379 % The format of the QueueAuthenticPixelsCache() method is:
4381 % PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4382 % const ssize_t y,const size_t columns,const size_t rows,
4383 % ExceptionInfo *exception)
4385 % A description of each parameter follows:
4387 % o image: the image.
4389 % o x,y,columns,rows: These values define the perimeter of a region of
4392 % o exception: return any errors or warnings in this structure.
4395 static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4396 const ssize_t y,const size_t columns,const size_t rows,
4397 ExceptionInfo *exception)
4403 id = GetOpenMPThreadId();
4405 cache_info=(CacheInfo *) image->cache;
4406 if (cache_info == (Cache) NULL)
4407 return((PixelPacket *) NULL);
4408 assert(id < (int) cache_info->number_threads);
4409 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4418 % Q u e u e A u t h e n t i c P i x e l s %
4422 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4424 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4425 % successfully intialized a pointer to a PixelPacket array representing the
4426 % region is returned, otherwise NULL is returned. The returned pointer may
4427 % point to a temporary working buffer for the pixels or it may point to the
4428 % final location of the pixels in memory.
4430 % Write-only access means that any existing pixel values corresponding to
4431 % the region are ignored. This is useful if the initial image is being
4432 % created from scratch, or if the existing pixel values are to be
4433 % completely replaced without need to refer to their pre-existing values.
4434 % The application is free to read and write the pixel buffer returned by
4435 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4436 % initialize the pixel array values. Initializing pixel array values is the
4437 % application's responsibility.
4439 % Performance is maximized if the selected region is part of one row, or
4440 % one or more full rows, since then there is opportunity to access the
4441 % pixels in-place (without a copy) if the image is in memory, or in a
4442 % memory-mapped file. The returned pointer must *never* be deallocated
4445 % Pixels accessed via the returned pointer represent a simple array of type
4446 % PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4447 % call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4448 % the black color component or the colormap indexes (of type IndexPacket)
4449 % corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4450 % array has been updated, the changes must be saved back to the underlying
4451 % image using SyncAuthenticPixels() or they may be lost.
4453 % The format of the QueueAuthenticPixels() method is:
4455 % PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4456 % const ssize_t y,const size_t columns,const size_t rows,
4457 % ExceptionInfo *exception)
4459 % A description of each parameter follows:
4461 % o image: the image.
4463 % o x,y,columns,rows: These values define the perimeter of a region of
4466 % o exception: return any errors or warnings in this structure.
4469 MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4470 const ssize_t y,const size_t columns,const size_t rows,
4471 ExceptionInfo *exception)
4477 id = GetOpenMPThreadId();
4479 assert(image != (Image *) NULL);
4480 assert(image->signature == MagickSignature);
4481 assert(image->cache != (Cache) NULL);
4482 cache_info=(CacheInfo *) image->cache;
4483 assert(cache_info->signature == MagickSignature);
4484 if (cache_info->methods.queue_authentic_pixels_handler !=
4485 (QueueAuthenticPixelsHandler) NULL)
4486 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4488 assert(id < (int) cache_info->number_threads);
4489 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4494 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4498 + R e a d P i x e l C a c h e I n d e x e s %
4502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4504 % ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4507 % The format of the ReadPixelCacheIndexes() method is:
4509 % MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4510 % NexusInfo *nexus_info,ExceptionInfo *exception)
4512 % A description of each parameter follows:
4514 % o cache_info: the pixel cache.
4516 % o nexus_info: the cache nexus to read the colormap indexes.
4518 % o exception: return any errors or warnings in this structure.
4521 static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4522 NexusInfo *nexus_info,ExceptionInfo *exception)
4532 register IndexPacket
4541 if (cache_info->active_index_channel == MagickFalse)
4542 return(MagickFalse);
4543 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4545 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4546 nexus_info->region.x;
4547 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4548 rows=nexus_info->region.height;
4549 number_pixels=length*rows;
4550 q=nexus_info->indexes;
4551 switch (cache_info->type)
4556 register IndexPacket
4560 Read indexes from memory.
4562 if ((cache_info->columns == nexus_info->region.width) &&
4563 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4565 length=number_pixels;
4568 p=cache_info->indexes+offset;
4569 for (y=0; y < (ssize_t) rows; y++)
4571 (void) memcpy(q,p,(size_t) length);
4572 p+=cache_info->columns;
4573 q+=nexus_info->region.width;
4580 Read indexes from disk.
4582 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4584 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4585 cache_info->cache_filename);
4586 return(MagickFalse);
4588 if ((cache_info->columns == nexus_info->region.width) &&
4589 (number_pixels < MagickMaxBufferExtent))
4591 length=number_pixels;
4594 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4595 for (y=0; y < (ssize_t) rows; y++)
4597 count=ReadPixelCacheRegion(cache_info,cache_info->offset+number_pixels*
4598 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4599 if ((MagickSizeType) count < length)
4601 offset+=cache_info->columns;
4602 q+=nexus_info->region.width;
4604 if (y < (ssize_t) rows)
4606 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4607 cache_info->cache_filename);
4608 return(MagickFalse);
4615 if ((cache_info->debug != MagickFalse) &&
4616 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4617 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4618 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4619 nexus_info->region.width,(double) nexus_info->region.height,(double)
4620 nexus_info->region.x,(double) nexus_info->region.y);
4625 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4629 + R e a d P i x e l C a c h e P i x e l s %
4633 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4635 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4638 % The format of the ReadPixelCachePixels() method is:
4640 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4641 % NexusInfo *nexus_info,ExceptionInfo *exception)
4643 % A description of each parameter follows:
4645 % o cache_info: the pixel cache.
4647 % o nexus_info: the cache nexus to read the pixels.
4649 % o exception: return any errors or warnings in this structure.
4652 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4653 NexusInfo *nexus_info,ExceptionInfo *exception)
4663 register PixelPacket
4672 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4674 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4675 nexus_info->region.x;
4676 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4677 rows=nexus_info->region.height;
4678 number_pixels=length*rows;
4679 q=nexus_info->pixels;
4680 switch (cache_info->type)
4685 register PixelPacket
4689 Read pixels from memory.
4691 if ((cache_info->columns == nexus_info->region.width) &&
4692 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
4694 length=number_pixels;
4697 p=cache_info->pixels+offset;
4698 for (y=0; y < (ssize_t) rows; y++)
4700 (void) memcpy(q,p,(size_t) length);
4701 p+=cache_info->columns;
4702 q+=nexus_info->region.width;
4709 Read pixels from disk.
4711 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4713 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4714 cache_info->cache_filename);
4715 return(MagickFalse);
4717 if ((cache_info->columns == nexus_info->region.width) &&
4718 (number_pixels < MagickMaxBufferExtent))
4720 length=number_pixels;
4723 for (y=0; y < (ssize_t) rows; y++)
4725 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4726 sizeof(*q),length,(unsigned char *) q);
4727 if ((MagickSizeType) count < length)
4729 offset+=cache_info->columns;
4730 q+=nexus_info->region.width;
4732 if (y < (ssize_t) rows)
4734 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4735 cache_info->cache_filename);
4736 return(MagickFalse);
4743 if ((cache_info->debug != MagickFalse) &&
4744 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4745 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4746 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4747 nexus_info->region.width,(double) nexus_info->region.height,(double)
4748 nexus_info->region.x,(double) nexus_info->region.y);
4753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4757 + R e f e r e n c e P i x e l C a c h e %
4761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4763 % ReferencePixelCache() increments the reference count associated with the
4764 % pixel cache returning a pointer to the cache.
4766 % The format of the ReferencePixelCache method is:
4768 % Cache ReferencePixelCache(Cache cache_info)
4770 % A description of each parameter follows:
4772 % o cache_info: the pixel cache.
4775 MagickExport Cache ReferencePixelCache(Cache cache)
4780 assert(cache != (Cache *) NULL);
4781 cache_info=(CacheInfo *) cache;
4782 assert(cache_info->signature == MagickSignature);
4783 LockSemaphoreInfo(cache_info->semaphore);
4784 cache_info->reference_count++;
4785 UnlockSemaphoreInfo(cache_info->semaphore);
4790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4794 + S e t P i x e l C a c h e M e t h o d s %
4798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4800 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4802 % The format of the SetPixelCacheMethods() method is:
4804 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4806 % A description of each parameter follows:
4808 % o cache: the pixel cache.
4810 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4813 MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4818 GetOneAuthenticPixelFromHandler
4819 get_one_authentic_pixel_from_handler;
4821 GetOneVirtualPixelFromHandler
4822 get_one_virtual_pixel_from_handler;
4825 Set cache pixel methods.
4827 assert(cache != (Cache) NULL);
4828 assert(cache_methods != (CacheMethods *) NULL);
4829 cache_info=(CacheInfo *) cache;
4830 assert(cache_info->signature == MagickSignature);
4831 if (cache_info->debug != MagickFalse)
4832 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4833 cache_info->filename);
4834 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4835 cache_info->methods.get_virtual_pixel_handler=
4836 cache_methods->get_virtual_pixel_handler;
4837 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4838 cache_info->methods.destroy_pixel_handler=
4839 cache_methods->destroy_pixel_handler;
4840 if (cache_methods->get_virtual_indexes_from_handler !=
4841 (GetVirtualIndexesFromHandler) NULL)
4842 cache_info->methods.get_virtual_indexes_from_handler=
4843 cache_methods->get_virtual_indexes_from_handler;
4844 if (cache_methods->get_authentic_pixels_handler !=
4845 (GetAuthenticPixelsHandler) NULL)
4846 cache_info->methods.get_authentic_pixels_handler=
4847 cache_methods->get_authentic_pixels_handler;
4848 if (cache_methods->queue_authentic_pixels_handler !=
4849 (QueueAuthenticPixelsHandler) NULL)
4850 cache_info->methods.queue_authentic_pixels_handler=
4851 cache_methods->queue_authentic_pixels_handler;
4852 if (cache_methods->sync_authentic_pixels_handler !=
4853 (SyncAuthenticPixelsHandler) NULL)
4854 cache_info->methods.sync_authentic_pixels_handler=
4855 cache_methods->sync_authentic_pixels_handler;
4856 if (cache_methods->get_authentic_pixels_from_handler !=
4857 (GetAuthenticPixelsFromHandler) NULL)
4858 cache_info->methods.get_authentic_pixels_from_handler=
4859 cache_methods->get_authentic_pixels_from_handler;
4860 if (cache_methods->get_authentic_indexes_from_handler !=
4861 (GetAuthenticIndexesFromHandler) NULL)
4862 cache_info->methods.get_authentic_indexes_from_handler=
4863 cache_methods->get_authentic_indexes_from_handler;
4864 get_one_virtual_pixel_from_handler=
4865 cache_info->methods.get_one_virtual_pixel_from_handler;
4866 if (get_one_virtual_pixel_from_handler !=
4867 (GetOneVirtualPixelFromHandler) NULL)
4868 cache_info->methods.get_one_virtual_pixel_from_handler=
4869 cache_methods->get_one_virtual_pixel_from_handler;
4870 get_one_authentic_pixel_from_handler=
4871 cache_methods->get_one_authentic_pixel_from_handler;
4872 if (get_one_authentic_pixel_from_handler !=
4873 (GetOneAuthenticPixelFromHandler) NULL)
4874 cache_info->methods.get_one_authentic_pixel_from_handler=
4875 cache_methods->get_one_authentic_pixel_from_handler;
4879 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4883 + S e t P i x e l C a c h e N e x u s P i x e l s %
4887 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4889 % SetPixelCacheNexusPixels() defines the region of the cache for the
4890 % specified cache nexus.
4892 % The format of the SetPixelCacheNexusPixels() method is:
4894 % PixelPacket SetPixelCacheNexusPixels(const Image *image,
4895 % const RectangleInfo *region,NexusInfo *nexus_info,
4896 % ExceptionInfo *exception)
4898 % A description of each parameter follows:
4900 % o image: the image.
4902 % o region: A pointer to the RectangleInfo structure that defines the
4903 % region of this particular cache nexus.
4905 % o nexus_info: the cache nexus to set.
4907 % o exception: return any errors or warnings in this structure.
4911 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4912 NexusInfo *nexus_info,ExceptionInfo *exception)
4914 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4915 return(MagickFalse);
4916 nexus_info->mapped=MagickFalse;
4917 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4918 nexus_info->length);
4919 if (nexus_info->cache == (PixelPacket *) NULL)
4921 nexus_info->mapped=MagickTrue;
4922 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4923 nexus_info->length);
4925 if (nexus_info->cache == (PixelPacket *) NULL)
4927 (void) ThrowMagickException(exception,GetMagickModule(),
4928 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4929 cache_info->filename);
4930 return(MagickFalse);
4935 static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4936 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4948 cache_info=(CacheInfo *) image->cache;
4949 assert(cache_info->signature == MagickSignature);
4950 if (cache_info->type == UndefinedCache)
4951 return((PixelPacket *) NULL);
4952 nexus_info->region=(*region);
4953 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4954 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
4960 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4961 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4962 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4963 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4964 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
4965 ((nexus_info->region.width == cache_info->columns) ||
4966 ((nexus_info->region.width % cache_info->columns) == 0)))))
4972 Pixels are accessed directly from memory.
4974 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4975 nexus_info->region.x;
4976 nexus_info->pixels=cache_info->pixels+offset;
4977 nexus_info->indexes=(IndexPacket *) NULL;
4978 if (cache_info->active_index_channel != MagickFalse)
4979 nexus_info->indexes=cache_info->indexes+offset;
4980 return(nexus_info->pixels);
4984 Pixels are stored in a cache region until they are synced to the cache.
4986 number_pixels=(MagickSizeType) nexus_info->region.width*
4987 nexus_info->region.height;
4988 length=number_pixels*sizeof(PixelPacket);
4989 if (cache_info->active_index_channel != MagickFalse)
4990 length+=number_pixels*sizeof(IndexPacket);
4991 if (nexus_info->cache == (PixelPacket *) NULL)
4993 nexus_info->length=length;
4994 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
4995 if (status == MagickFalse)
4997 nexus_info->length=0;
4998 return((PixelPacket *) NULL);
5002 if (nexus_info->length != length)
5004 RelinquishCacheNexusPixels(nexus_info);
5005 nexus_info->length=length;
5006 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5007 if (status == MagickFalse)
5009 nexus_info->length=0;
5010 return((PixelPacket *) NULL);
5013 nexus_info->pixels=nexus_info->cache;
5014 nexus_info->indexes=(IndexPacket *) NULL;
5015 if (cache_info->active_index_channel != MagickFalse)
5016 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5017 return(nexus_info->pixels);
5021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5025 % 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 %
5029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5031 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5032 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5033 % access that is outside the boundaries of the image cache.
5035 % The format of the SetPixelCacheVirtualMethod() method is:
5037 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5038 % const VirtualPixelMethod virtual_pixel_method)
5040 % A description of each parameter follows:
5042 % o image: the image.
5044 % o virtual_pixel_method: choose the type of virtual pixel.
5047 MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5048 const VirtualPixelMethod virtual_pixel_method)
5056 assert(image != (Image *) NULL);
5057 assert(image->signature == MagickSignature);
5058 if (image->debug != MagickFalse)
5059 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5060 assert(image->cache != (Cache) NULL);
5061 cache_info=(CacheInfo *) image->cache;
5062 assert(cache_info->signature == MagickSignature);
5063 method=cache_info->virtual_pixel_method;
5064 cache_info->virtual_pixel_method=virtual_pixel_method;
5069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5073 + 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 %
5077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5079 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5080 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5081 % is synced, otherwise MagickFalse.
5083 % The format of the SyncAuthenticPixelCacheNexus() method is:
5085 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5086 % NexusInfo *nexus_info,ExceptionInfo *exception)
5088 % A description of each parameter follows:
5090 % o image: the image.
5092 % o nexus_info: the cache nexus to sync.
5094 % o exception: return any errors or warnings in this structure.
5097 MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5098 NexusInfo *nexus_info,ExceptionInfo *exception)
5107 Transfer pixels to the cache.
5109 assert(image != (Image *) NULL);
5110 assert(image->signature == MagickSignature);
5111 if (image->cache == (Cache) NULL)
5112 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5113 cache_info=(CacheInfo *) image->cache;
5114 if (cache_info->type == UndefinedCache)
5115 return(MagickFalse);
5116 if ((image->clip_mask != (Image *) NULL) &&
5117 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5118 return(MagickFalse);
5119 if ((image->mask != (Image *) NULL) &&
5120 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5121 return(MagickFalse);
5122 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5124 assert(cache_info->signature == MagickSignature);
5125 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5126 if ((cache_info->active_index_channel != MagickFalse) &&
5127 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5128 return(MagickFalse);
5133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5137 + S y n c A u t h e n t i c P i x e l C a c h e %
5141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5143 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5144 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5145 % otherwise MagickFalse.
5147 % The format of the SyncAuthenticPixelsCache() method is:
5149 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5150 % ExceptionInfo *exception)
5152 % A description of each parameter follows:
5154 % o image: the image.
5156 % o exception: return any errors or warnings in this structure.
5159 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5160 ExceptionInfo *exception)
5166 id = GetOpenMPThreadId();
5168 cache_info=(CacheInfo *) image->cache;
5169 assert(id < (int) cache_info->number_threads);
5170 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5179 % S y n c A u t h e n t i c P i x e l s %
5183 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5185 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5186 % The method returns MagickTrue if the pixel region is flushed, otherwise
5189 % The format of the SyncAuthenticPixels() method is:
5191 % MagickBooleanType SyncAuthenticPixels(Image *image,
5192 % ExceptionInfo *exception)
5194 % A description of each parameter follows:
5196 % o image: the image.
5198 % o exception: return any errors or warnings in this structure.
5201 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5202 ExceptionInfo *exception)
5208 id = GetOpenMPThreadId();
5210 assert(image != (Image *) NULL);
5211 assert(image->signature == MagickSignature);
5212 assert(image->cache != (Cache) NULL);
5213 cache_info=(CacheInfo *) image->cache;
5214 assert(cache_info->signature == MagickSignature);
5215 if (cache_info->methods.sync_authentic_pixels_handler !=
5216 (SyncAuthenticPixelsHandler) NULL)
5217 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5218 assert(id < (int) cache_info->number_threads);
5219 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5228 + W r i t e P i x e l C a c h e I n d e x e s %
5232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5234 % WritePixelCacheIndexes() writes the colormap indexes to the specified
5235 % region of the pixel cache.
5237 % The format of the WritePixelCacheIndexes() method is:
5239 % MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5240 % NexusInfo *nexus_info,ExceptionInfo *exception)
5242 % A description of each parameter follows:
5244 % o cache_info: the pixel cache.
5246 % o nexus_info: the cache nexus to write the colormap indexes.
5248 % o exception: return any errors or warnings in this structure.
5251 static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5252 NexusInfo *nexus_info,ExceptionInfo *exception)
5262 register const IndexPacket
5271 if (cache_info->active_index_channel == MagickFalse)
5272 return(MagickFalse);
5273 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5275 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5276 nexus_info->region.x;
5277 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5278 rows=nexus_info->region.height;
5279 number_pixels=(MagickSizeType) length*rows;
5280 p=nexus_info->indexes;
5281 switch (cache_info->type)
5286 register IndexPacket
5290 Write indexes to memory.
5292 if ((cache_info->columns == nexus_info->region.width) &&
5293 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5295 length=number_pixels;
5298 q=cache_info->indexes+offset;
5299 for (y=0; y < (ssize_t) rows; y++)
5301 (void) memcpy(q,p,(size_t) length);
5302 p+=nexus_info->region.width;
5303 q+=cache_info->columns;
5310 Write indexes to disk.
5312 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5314 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5315 cache_info->cache_filename);
5316 return(MagickFalse);
5318 if ((cache_info->columns == nexus_info->region.width) &&
5319 (number_pixels < MagickMaxBufferExtent))
5321 length=number_pixels;
5324 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
5325 for (y=0; y < (ssize_t) rows; y++)
5327 count=WritePixelCacheRegion(cache_info,cache_info->offset+number_pixels*
5328 sizeof(PixelPacket)+offset*sizeof(*p),length,
5329 (const unsigned char *) p);
5330 if ((MagickSizeType) count < length)
5332 p+=nexus_info->region.width;
5333 offset+=cache_info->columns;
5335 if (y < (ssize_t) rows)
5337 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5338 cache_info->cache_filename);
5339 return(MagickFalse);
5346 if ((cache_info->debug != MagickFalse) &&
5347 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5348 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5349 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5350 nexus_info->region.width,(double) nexus_info->region.height,(double)
5351 nexus_info->region.x,(double) nexus_info->region.y);
5356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5360 + W r i t e C a c h e P i x e l s %
5364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5366 % WritePixelCachePixels() writes image pixels to the specified region of the
5369 % The format of the WritePixelCachePixels() method is:
5371 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5372 % NexusInfo *nexus_info,ExceptionInfo *exception)
5374 % A description of each parameter follows:
5376 % o cache_info: the pixel cache.
5378 % o nexus_info: the cache nexus to write the pixels.
5380 % o exception: return any errors or warnings in this structure.
5383 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5384 NexusInfo *nexus_info,ExceptionInfo *exception)
5394 register const PixelPacket
5403 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5405 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5406 nexus_info->region.x;
5407 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5408 rows=nexus_info->region.height;
5409 number_pixels=length*rows;
5410 p=nexus_info->pixels;
5411 switch (cache_info->type)
5416 register PixelPacket
5420 Write pixels to memory.
5422 if ((cache_info->columns == nexus_info->region.width) &&
5423 (number_pixels == (MagickSizeType) ((size_t) number_pixels)))
5425 length=number_pixels;
5428 q=cache_info->pixels+offset;
5429 for (y=0; y < (ssize_t) rows; y++)
5431 (void) memcpy(q,p,(size_t) length);
5432 p+=nexus_info->region.width;
5433 q+=cache_info->columns;
5440 Write pixels to disk.
5442 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5444 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5445 cache_info->cache_filename);
5446 return(MagickFalse);
5448 if ((cache_info->columns == nexus_info->region.width) &&
5449 (number_pixels < MagickMaxBufferExtent))
5451 length=number_pixels;
5454 for (y=0; y < (ssize_t) rows; y++)
5456 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5457 sizeof(*p),length,(const unsigned char *) p);
5458 if ((MagickSizeType) count < length)
5460 p+=nexus_info->region.width;
5461 offset+=cache_info->columns;
5463 if (y < (ssize_t) rows)
5465 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5466 cache_info->cache_filename);
5467 return(MagickFalse);
5474 if ((cache_info->debug != MagickFalse) &&
5475 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5476 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5477 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5478 nexus_info->region.width,(double) nexus_info->region.height,(double)
5479 nexus_info->region.x,(double) nexus_info->region.y);