2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % CCCC AAA CCCC H H EEEEE %
8 % C AAAAA C HHHHH EEE %
10 % CCCC A A CCCC H H EEEEE %
13 % MagickCore Pixel Cache Methods %
20 % Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "magick/studio.h"
44 #include "magick/blob.h"
45 #include "magick/blob-private.h"
46 #include "magick/cache.h"
47 #include "magick/cache-private.h"
48 #include "magick/color-private.h"
49 #include "magick/composite-private.h"
50 #include "magick/exception.h"
51 #include "magick/exception-private.h"
52 #include "magick/geometry.h"
53 #include "magick/list.h"
54 #include "magick/log.h"
55 #include "magick/magick.h"
56 #include "magick/memory_.h"
57 #include "magick/pixel.h"
58 #include "magick/pixel-private.h"
59 #include "magick/policy.h"
60 #include "magick/quantum.h"
61 #include "magick/random_.h"
62 #include "magick/resource_.h"
63 #include "magick/semaphore.h"
64 #include "magick/splay-tree.h"
65 #include "magick/string_.h"
66 #include "magick/string-private.h"
67 #include "magick/thread-private.h"
68 #include "magick/utility.h"
69 #if defined(MAGICKCORE_ZLIB_DELEGATE)
76 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
81 typedef struct _MagickModulo
111 Forward declarations.
113 #if defined(__cplusplus) || defined(c_plusplus)
117 static const IndexPacket
118 *GetVirtualIndexesFromCache(const Image *);
120 static const PixelPacket
121 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
122 const ssize_t,const size_t,const size_t,ExceptionInfo *),
123 *GetVirtualPixelsCache(const Image *);
125 static MagickBooleanType
126 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
127 PixelPacket *,ExceptionInfo *),
128 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
129 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
130 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
131 ReadPixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
132 ReadPixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *),
133 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
134 WritePixelCacheIndexes(CacheInfo *,NexusInfo *,ExceptionInfo *),
135 WritePixelCachePixels(CacheInfo *,NexusInfo *,ExceptionInfo *);
138 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
139 const size_t,ExceptionInfo *),
140 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const size_t,
141 const size_t,ExceptionInfo *),
142 *SetPixelCacheNexusPixels(const Image *,const RectangleInfo *,NexusInfo *,
145 #if defined(__cplusplus) || defined(c_plusplus)
152 static volatile MagickBooleanType
153 instantiate_cache = MagickFalse;
156 *cache_semaphore = (SemaphoreInfo *) NULL;
159 *cache_resources = (SplayTreeInfo *) NULL;
162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
166 + A c q u i r e P i x e l C a c h e %
170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 % AcquirePixelCache() acquires a pixel cache.
174 % The format of the AcquirePixelCache() method is:
176 % Cache AcquirePixelCache(const size_t number_threads)
178 % A description of each parameter follows:
180 % o number_threads: the number of nexus threads.
183 MagickExport Cache AcquirePixelCache(const size_t number_threads)
188 cache_info=(CacheInfo *) AcquireMagickMemory(sizeof(*cache_info));
189 if (cache_info == (CacheInfo *) NULL)
190 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
191 (void) ResetMagickMemory(cache_info,0,sizeof(*cache_info));
192 cache_info->type=UndefinedCache;
193 cache_info->mode=IOMode;
194 cache_info->colorspace=RGBColorspace;
195 cache_info->file=(-1);
196 cache_info->id=GetMagickThreadId();
197 cache_info->number_threads=number_threads;
198 if (number_threads == 0)
199 cache_info->number_threads=GetOpenMPMaximumThreads();
200 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
201 if (cache_info->nexus_info == (NexusInfo **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
203 cache_info->semaphore=AllocateSemaphoreInfo();
204 cache_info->reference_count=1;
205 cache_info->disk_semaphore=AllocateSemaphoreInfo();
206 cache_info->debug=IsEventLogging();
207 cache_info->signature=MagickSignature;
208 if ((cache_resources == (SplayTreeInfo *) NULL) &&
209 (instantiate_cache == MagickFalse))
211 if (cache_semaphore == (SemaphoreInfo *) NULL)
212 AcquireSemaphoreInfo(&cache_semaphore);
213 LockSemaphoreInfo(cache_semaphore);
214 if ((cache_resources == (SplayTreeInfo *) NULL) &&
215 (instantiate_cache == MagickFalse))
217 cache_resources=NewSplayTree((int (*)(const void *,const void *))
218 NULL,(void *(*)(void *)) NULL,(void *(*)(void *)) NULL);
219 instantiate_cache=MagickTrue;
221 UnlockSemaphoreInfo(cache_semaphore);
223 (void) AddValueToSplayTree(cache_resources,cache_info,cache_info);
224 return((Cache ) cache_info);
228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232 % A c q u i r e P i x e l C a c h e N e x u s %
236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238 % AcquirePixelCacheNexus() allocates the NexusInfo structure.
240 % The format of the AcquirePixelCacheNexus method is:
242 % NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
244 % A description of each parameter follows:
246 % o number_threads: the number of nexus threads.
249 MagickExport NexusInfo **AcquirePixelCacheNexus(const size_t number_threads)
257 nexus_info=(NexusInfo **) AcquireQuantumMemory(number_threads,
258 sizeof(*nexus_info));
259 if (nexus_info == (NexusInfo **) NULL)
260 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
261 for (i=0; i < (ssize_t) number_threads; i++)
263 nexus_info[i]=(NexusInfo *) AcquireAlignedMemory(1,sizeof(**nexus_info));
264 if (nexus_info[i] == (NexusInfo *) NULL)
265 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
266 (void) ResetMagickMemory(nexus_info[i],0,sizeof(*nexus_info[i]));
267 nexus_info[i]->signature=MagickSignature;
273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277 + A c q u i r e P i x e l C a c h e P i x e l s %
281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283 % AcquirePixelCachePixels() returns the pixels associated with the specified
286 % The format of the AcquirePixelCachePixels() method is:
288 % const void *AcquirePixelCachePixels(const Image *image,
289 % MagickSizeType *length,ExceptionInfo *exception)
291 % A description of each parameter follows:
293 % o image: the image.
295 % o length: the pixel cache length.
297 % o exception: return any errors or warnings in this structure.
300 MagickExport const void *AcquirePixelCachePixels(const Image *image,
301 MagickSizeType *length,ExceptionInfo *exception)
306 assert(image != (const Image *) NULL);
307 assert(image->signature == MagickSignature);
308 assert(exception != (ExceptionInfo *) NULL);
309 assert(exception->signature == MagickSignature);
310 assert(image->cache != (Cache) NULL);
311 cache_info=(CacheInfo *) image->cache;
312 assert(cache_info->signature == MagickSignature);
314 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
315 return((const void *) NULL);
316 *length=cache_info->length;
317 return((const void *) cache_info->pixels);
321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325 + C a c h e C o m p o n e n t G e n e s i s %
329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331 % CacheComponentGenesis() instantiates the cache component.
333 % The format of the CacheComponentGenesis method is:
335 % MagickBooleanType CacheComponentGenesis(void)
338 MagickExport MagickBooleanType CacheComponentGenesis(void)
340 AcquireSemaphoreInfo(&cache_semaphore);
345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
349 + C a c h e C o m p o n e n t T e r m i n u s %
353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355 % CacheComponentTerminus() destroys the cache component.
357 % The format of the CacheComponentTerminus() method is:
359 % CacheComponentTerminus(void)
362 MagickExport void CacheComponentTerminus(void)
364 if (cache_semaphore == (SemaphoreInfo *) NULL)
365 AcquireSemaphoreInfo(&cache_semaphore);
366 LockSemaphoreInfo(cache_semaphore);
367 if (cache_resources != (SplayTreeInfo *) NULL)
368 cache_resources=DestroySplayTree(cache_resources);
369 instantiate_cache=MagickFalse;
370 UnlockSemaphoreInfo(cache_semaphore);
371 DestroySemaphoreInfo(&cache_semaphore);
375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379 + C l i p P i x e l C a c h e N e x u s %
383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385 % ClipPixelCacheNexus() clips the cache nexus as defined by the image clip
386 % mask. The method returns MagickTrue if the pixel region is clipped,
387 % otherwise MagickFalse.
389 % The format of the ClipPixelCacheNexus() method is:
391 % MagickBooleanType ClipPixelCacheNexus(Image *image,NexusInfo *nexus_info,
392 % ExceptionInfo *exception)
394 % A description of each parameter follows:
396 % o image: the image.
398 % o nexus_info: the cache nexus to clip.
400 % o exception: return any errors or warnings in this structure.
403 static MagickBooleanType ClipPixelCacheNexus(Image *image,
404 NexusInfo *nexus_info,ExceptionInfo *exception)
416 register const PixelPacket
420 *restrict nexus_indexes,
433 if (image->debug != MagickFalse)
434 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
435 if (image->clip_mask == (Image *) NULL)
437 cache_info=(CacheInfo *) image->cache;
438 if (cache_info == (Cache) NULL)
440 image_nexus=AcquirePixelCacheNexus(1);
441 clip_nexus=AcquirePixelCacheNexus(1);
442 if ((image_nexus == (NexusInfo **) NULL) ||
443 (clip_nexus == (NexusInfo **) NULL))
444 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
445 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
446 nexus_info->region.width,nexus_info->region.height,image_nexus[0],
448 indexes=GetPixelCacheNexusIndexes(cache_info,image_nexus[0]);
449 q=nexus_info->pixels;
450 nexus_indexes=nexus_info->indexes;
451 r=GetVirtualPixelsFromNexus(image->clip_mask,MaskVirtualPixelMethod,
452 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
453 nexus_info->region.height,clip_nexus[0],exception);
454 number_pixels=(MagickSizeType) nexus_info->region.width*
455 nexus_info->region.height;
456 for (i=0; i < (ssize_t) number_pixels; i++)
458 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
460 if (PixelIntensityToQuantum(r) > ((Quantum) QuantumRange/2))
462 SetRedPixelComponent(q,GetRedPixelComponent(p));
463 SetGreenPixelComponent(q,GetGreenPixelComponent(p));
464 SetBluePixelComponent(q,GetBluePixelComponent(p));
465 SetOpacityPixelComponent(q,GetOpacityPixelComponent(p));
466 if (cache_info->active_index_channel != MagickFalse)
467 nexus_indexes[i]=indexes[i];
473 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
474 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
475 if (i < (ssize_t) number_pixels)
481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 + C l o n e P i x e l C a c h e %
489 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491 % ClonePixelCache() clones a pixel cache.
493 % The format of the ClonePixelCache() method is:
495 % Cache ClonePixelCache(const Cache cache)
497 % A description of each parameter follows:
499 % o cache: the pixel cache.
502 MagickExport Cache ClonePixelCache(const Cache cache)
510 assert(cache != (const Cache) NULL);
511 cache_info=(const CacheInfo *) cache;
512 assert(cache_info->signature == MagickSignature);
513 if (cache_info->debug != MagickFalse)
514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
515 cache_info->filename);
516 clone_info=(CacheInfo *) AcquirePixelCache(cache_info->number_threads);
517 if (clone_info == (Cache) NULL)
518 return((Cache) NULL);
519 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
520 return((Cache ) clone_info);
524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
528 + C l o n e P i x e l C a c h e P i x e l s %
532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %
533 % ClonePixelCachePixels() clones the source pixel cache to the destination
536 % The format of the ClonePixelCachePixels() method is:
538 % MagickBooleanType ClonePixelCachePixels(CacheInfo *cache_info,
539 % CacheInfo *source_info,ExceptionInfo *exception)
541 % A description of each parameter follows:
543 % o cache_info: the pixel cache.
545 % o source_info: the source pixel cache.
547 % o exception: return any errors or warnings in this structure.
551 static MagickBooleanType ClosePixelCacheOnDisk(CacheInfo *cache_info)
557 LockSemaphoreInfo(cache_info->disk_semaphore);
558 if (cache_info->file != -1)
559 status=close(cache_info->file);
560 cache_info->file=(-1);
561 RelinquishMagickResource(FileResource,1);
562 UnlockSemaphoreInfo(cache_info->disk_semaphore);
563 return(status == -1 ? MagickFalse : MagickTrue);
566 static void LimitPixelCacheDescriptors(void)
573 Limit # of open file descriptors.
575 if (GetMagickResource(FileResource) < GetMagickResourceLimit(FileResource))
577 LockSemaphoreInfo(cache_semaphore);
578 if (cache_resources == (SplayTreeInfo *) NULL)
580 UnlockSemaphoreInfo(cache_semaphore);
583 ResetSplayTreeIterator(cache_resources);
584 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
585 while (p != (CacheInfo *) NULL)
587 if ((p->type == DiskCache) && (p->file != -1))
589 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
591 for (q=p; p != (CacheInfo *) NULL; )
593 if ((p->type == DiskCache) && (p->file != -1) &&
594 (p->timestamp < q->timestamp))
596 p=(CacheInfo *) GetNextKeyInSplayTree(cache_resources);
598 if (q != (CacheInfo *) NULL)
601 Close least recently used cache.
603 (void) close(q->file);
606 UnlockSemaphoreInfo(cache_semaphore);
609 static inline MagickSizeType MagickMax(const MagickSizeType x,
610 const MagickSizeType y)
617 static inline MagickSizeType MagickMin(const MagickSizeType x,
618 const MagickSizeType y)
625 static MagickBooleanType OpenPixelCacheOnDisk(CacheInfo *cache_info,
632 Open pixel cache on disk.
634 LockSemaphoreInfo(cache_info->disk_semaphore);
635 if (cache_info->file != -1)
637 UnlockSemaphoreInfo(cache_info->disk_semaphore);
638 return(MagickTrue); /* cache already open */
640 LimitPixelCacheDescriptors();
641 if (*cache_info->cache_filename == '\0')
642 file=AcquireUniqueFileResource(cache_info->cache_filename);
648 file=open(cache_info->cache_filename,O_RDONLY | O_BINARY);
653 file=open(cache_info->cache_filename,O_WRONLY | O_CREAT | O_BINARY |
656 file=open(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
662 file=open(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
665 file=open(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
671 UnlockSemaphoreInfo(cache_info->disk_semaphore);
674 (void) AcquireMagickResource(FileResource,1);
675 cache_info->file=file;
676 cache_info->timestamp=time(0);
677 UnlockSemaphoreInfo(cache_info->disk_semaphore);
681 static inline MagickOffsetType ReadPixelCacheRegion(CacheInfo *cache_info,
682 const MagickOffsetType offset,const MagickSizeType length,
683 unsigned char *restrict buffer)
685 register MagickOffsetType
691 cache_info->timestamp=time(0);
692 #if !defined(MAGICKCORE_HAVE_PREAD)
693 LockSemaphoreInfo(cache_info->disk_semaphore);
694 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
696 UnlockSemaphoreInfo(cache_info->disk_semaphore);
697 return((MagickOffsetType) -1);
701 for (i=0; i < (MagickOffsetType) length; i+=count)
703 #if !defined(MAGICKCORE_HAVE_PREAD)
704 count=read(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
705 (MagickSizeType) SSIZE_MAX));
707 count=pread(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
708 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
719 #if !defined(MAGICKCORE_HAVE_PREAD)
720 UnlockSemaphoreInfo(cache_info->disk_semaphore);
725 static inline MagickOffsetType WritePixelCacheRegion(CacheInfo *cache_info,
726 const MagickOffsetType offset,const MagickSizeType length,
727 const unsigned char *restrict buffer)
729 register MagickOffsetType
735 cache_info->timestamp=time(0);
736 #if !defined(MAGICKCORE_HAVE_PWRITE)
737 LockSemaphoreInfo(cache_info->disk_semaphore);
738 if (MagickSeek(cache_info->file,offset,SEEK_SET) < 0)
740 UnlockSemaphoreInfo(cache_info->disk_semaphore);
741 return((MagickOffsetType) -1);
745 for (i=0; i < (MagickOffsetType) length; i+=count)
747 #if !defined(MAGICKCORE_HAVE_PWRITE)
748 count=write(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
749 (MagickSizeType) SSIZE_MAX));
751 count=pwrite(cache_info->file,buffer+i,(size_t) MagickMin(length-i,
752 (MagickSizeType) SSIZE_MAX),(off_t) (offset+i));
763 #if !defined(MAGICKCORE_HAVE_PWRITE)
764 UnlockSemaphoreInfo(cache_info->disk_semaphore);
769 static MagickBooleanType CloneDiskToDiskPixelCache(CacheInfo *clone_info,
770 CacheInfo *cache_info,ExceptionInfo *exception)
790 if (cache_info->debug != MagickFalse)
791 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => disk");
792 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
794 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
795 clone_info->cache_filename);
798 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
800 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
801 cache_info->cache_filename);
804 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
805 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
806 if ((clone_info->active_index_channel != MagickFalse) &&
807 (cache_info->active_index_channel != MagickFalse))
815 length=MagickMax(clone_info->columns,cache_info->columns)*
817 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
818 if (indexes == (IndexPacket *) NULL)
820 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
821 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
824 (void) ResetMagickMemory(indexes,0,(size_t) length);
825 length=columns*sizeof(*indexes);
826 source_offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
827 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
829 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
830 for (y=0; y < (ssize_t) rows; y++)
832 source_offset-=cache_info->columns*sizeof(*indexes);
833 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
834 length,(unsigned char *) indexes);
835 if ((MagickSizeType) count != length)
837 offset-=clone_info->columns*sizeof(*indexes);
838 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
839 (unsigned char *) indexes);
840 if ((MagickSizeType) count != length)
843 if (y < (ssize_t) rows)
845 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
846 ThrowFileException(exception,CacheError,"UnableToCloneCache",
847 cache_info->cache_filename);
850 if (clone_info->columns > cache_info->columns)
852 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
853 (void) ResetMagickMemory(indexes,0,(size_t) length);
854 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
855 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
856 for (y=0; y < (ssize_t) rows; y++)
858 offset-=clone_info->columns*sizeof(*indexes);
859 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
860 length,(unsigned char *) indexes);
861 if ((MagickSizeType) count != length)
864 if (y < (ssize_t) rows)
866 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
867 ThrowFileException(exception,CacheError,"UnableToCloneCache",
868 cache_info->cache_filename);
872 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
877 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
878 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
879 if (pixels == (PixelPacket *) NULL)
881 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
882 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
885 (void) ResetMagickMemory(pixels,0,(size_t) length);
886 length=columns*sizeof(*pixels);
887 source_offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
888 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
889 for (y=0; y < (ssize_t) rows; y++)
891 source_offset-=cache_info->columns*sizeof(*pixels);
892 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
893 length,(unsigned char *) pixels);
894 if ((MagickSizeType) count != length)
896 offset-=clone_info->columns*sizeof(*pixels);
897 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
898 (unsigned char *) pixels);
899 if ((MagickSizeType) count != length)
902 if (y < (ssize_t) rows)
904 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
905 ThrowFileException(exception,CacheError,"UnableToCloneCache",
906 cache_info->cache_filename);
909 if (clone_info->columns > cache_info->columns)
911 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
913 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
914 (void) ResetMagickMemory(pixels,0,(size_t) length);
915 for (y=0; y < (ssize_t) rows; y++)
917 offset-=clone_info->columns*sizeof(*pixels);
918 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
919 (unsigned char *) pixels);
920 if ((MagickSizeType) count != length)
923 if (y < (ssize_t) rows)
925 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
926 ThrowFileException(exception,CacheError,"UnableToCloneCache",
927 cache_info->cache_filename);
931 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
935 static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
936 CacheInfo *cache_info,ExceptionInfo *exception)
956 if (cache_info->debug != MagickFalse)
957 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
958 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
960 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
961 cache_info->cache_filename);
964 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
965 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
966 if ((clone_info->active_index_channel != MagickFalse) &&
967 (cache_info->active_index_channel != MagickFalse))
976 length=MagickMax(clone_info->columns,cache_info->columns)*
978 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
979 if (indexes == (IndexPacket *) NULL)
981 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
982 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
985 (void) ResetMagickMemory(indexes,0,(size_t) length);
986 length=columns*sizeof(IndexPacket);
987 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988 sizeof(*pixels)+cache_info->columns*rows*sizeof(*indexes);
989 q=clone_info->indexes+clone_info->columns*rows;
990 for (y=0; y < (ssize_t) rows; y++)
992 offset-=cache_info->columns*sizeof(IndexPacket);
993 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
994 length,(unsigned char *) indexes);
995 if ((MagickSizeType) count != length)
997 q-=clone_info->columns;
998 (void) memcpy(q,indexes,(size_t) length);
999 if ((MagickSizeType) count != length)
1002 if (y < (ssize_t) rows)
1004 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1005 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1006 cache_info->cache_filename);
1007 return(MagickFalse);
1009 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1014 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1015 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1016 if (pixels == (PixelPacket *) NULL)
1018 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1019 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1020 return(MagickFalse);
1022 (void) ResetMagickMemory(pixels,0,(size_t) length);
1023 length=columns*sizeof(*pixels);
1024 offset=(MagickOffsetType) cache_info->columns*rows*sizeof(*pixels);
1025 q=clone_info->pixels+clone_info->columns*rows;
1026 for (y=0; y < (ssize_t) rows; y++)
1028 offset-=cache_info->columns*sizeof(*pixels);
1029 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1030 (unsigned char *) pixels);
1031 if ((MagickSizeType) count != length)
1033 q-=clone_info->columns;
1034 (void) memcpy(q,pixels,(size_t) length);
1036 if (y < (ssize_t) rows)
1038 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1039 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1040 cache_info->cache_filename);
1041 return(MagickFalse);
1043 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1047 static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1048 CacheInfo *cache_info,ExceptionInfo *exception)
1057 register PixelPacket
1068 if (cache_info->debug != MagickFalse)
1069 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1070 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1072 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1073 clone_info->cache_filename);
1074 return(MagickFalse);
1076 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1077 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1078 if ((clone_info->active_index_channel != MagickFalse) &&
1079 (cache_info->active_index_channel != MagickFalse))
1081 register IndexPacket
1086 Clone cache indexes.
1088 length=MagickMax(clone_info->columns,cache_info->columns)*
1090 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1091 if (indexes == (IndexPacket *) NULL)
1093 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1094 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1095 return(MagickFalse);
1097 (void) ResetMagickMemory(indexes,0,(size_t) length);
1098 length=columns*sizeof(*indexes);
1099 p=cache_info->indexes+cache_info->columns*rows;
1100 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101 sizeof(*pixels)+clone_info->columns*rows*sizeof(*indexes);
1102 for (y=0; y < (ssize_t) rows; y++)
1104 p-=cache_info->columns;
1105 (void) memcpy(indexes,p,(size_t) length);
1106 offset-=clone_info->columns*sizeof(*indexes);
1107 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1108 (unsigned char *) indexes);
1109 if ((MagickSizeType) count != length)
1112 if (y < (ssize_t) rows)
1114 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1115 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1116 cache_info->cache_filename);
1117 return(MagickFalse);
1119 if (clone_info->columns > cache_info->columns)
1121 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1122 (void) ResetMagickMemory(indexes,0,(size_t) length);
1123 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124 sizeof(*pixels)+(clone_info->columns*rows+columns)*sizeof(*indexes);
1125 for (y=0; y < (ssize_t) rows; y++)
1127 offset-=clone_info->columns*sizeof(*indexes);
1128 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1129 length,(unsigned char *) indexes);
1130 if ((MagickSizeType) count != length)
1133 if (y < (ssize_t) rows)
1135 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1136 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1137 cache_info->cache_filename);
1138 return(MagickFalse);
1141 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1146 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1147 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1148 if (pixels == (PixelPacket *) NULL)
1150 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1151 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1152 return(MagickFalse);
1154 (void) ResetMagickMemory(pixels,0,(size_t) length);
1155 length=columns*sizeof(*pixels);
1156 p=cache_info->pixels+cache_info->columns*rows;
1157 offset=(MagickOffsetType) clone_info->columns*rows*sizeof(*pixels);
1158 for (y=0; y < (ssize_t) rows; y++)
1160 p-=cache_info->columns;
1161 (void) memcpy(pixels,p,(size_t) length);
1162 offset-=clone_info->columns*sizeof(*pixels);
1163 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1164 (unsigned char *) pixels);
1165 if ((MagickSizeType) count != length)
1168 if (y < (ssize_t) rows)
1170 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1171 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1172 cache_info->cache_filename);
1173 return(MagickFalse);
1175 if (clone_info->columns > cache_info->columns)
1177 offset=(MagickOffsetType) (clone_info->columns*rows+columns)*
1179 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1180 (void) ResetMagickMemory(pixels,0,(size_t) length);
1181 for (y=0; y < (ssize_t) rows; y++)
1183 offset-=clone_info->columns*sizeof(*pixels);
1184 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1185 (unsigned char *) pixels);
1186 if ((MagickSizeType) count != length)
1189 if (y < (ssize_t) rows)
1191 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1192 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1193 cache_info->cache_filename);
1194 return(MagickFalse);
1197 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1201 static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1202 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1204 register PixelPacket
1206 *restrict source_pixels;
1216 if (cache_info->debug != MagickFalse)
1217 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
1218 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1219 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1220 if ((clone_info->active_index_channel != MagickFalse) &&
1221 (cache_info->active_index_channel != MagickFalse))
1223 register IndexPacket
1228 Clone cache indexes.
1230 length=columns*sizeof(*indexes);
1231 if (clone_info->columns == cache_info->columns)
1232 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
1235 source_indexes=cache_info->indexes+cache_info->columns*rows;
1236 indexes=clone_info->indexes+clone_info->columns*rows;
1237 for (y=0; y < (ssize_t) rows; y++)
1239 source_indexes-=cache_info->columns;
1240 indexes-=clone_info->columns;
1241 (void) memcpy(indexes,source_indexes,length);
1243 if (clone_info->columns > cache_info->columns)
1245 length=(clone_info->columns-cache_info->columns)*
1247 indexes=clone_info->indexes+clone_info->columns*rows+
1248 cache_info->columns;
1249 for (y=0; y < (ssize_t) rows; y++)
1251 indexes-=clone_info->columns;
1252 (void) ResetMagickMemory(indexes,0,length);
1260 length=columns*sizeof(*pixels);
1261 if (clone_info->columns == cache_info->columns)
1262 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
1265 source_pixels=cache_info->pixels+cache_info->columns*rows;
1266 pixels=clone_info->pixels+clone_info->columns*rows;
1267 for (y=0; y < (ssize_t) rows; y++)
1269 source_pixels-=cache_info->columns;
1270 pixels-=clone_info->columns;
1271 (void) memcpy(pixels,source_pixels,length);
1273 if (clone_info->columns > cache_info->columns)
1275 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1276 pixels=clone_info->pixels+clone_info->columns*rows+
1277 cache_info->columns;
1278 for (y=0; y < (ssize_t) rows; y++)
1280 pixels-=clone_info->columns;
1281 (void) ResetMagickMemory(pixels,0,length);
1288 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1289 CacheInfo *cache_info,ExceptionInfo *exception)
1291 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1292 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1293 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1294 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1295 if (cache_info->type == DiskCache)
1296 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1297 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305 + C l o n e P i x e l C a c h e M e t h o d s %
1309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1311 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1314 % The format of the ClonePixelCacheMethods() method is:
1316 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1318 % A description of each parameter follows:
1320 % o clone: Specifies a pointer to a Cache structure.
1322 % o cache: the pixel cache.
1325 MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1331 assert(clone != (Cache) NULL);
1332 source_info=(CacheInfo *) clone;
1333 assert(source_info->signature == MagickSignature);
1334 if (source_info->debug != MagickFalse)
1335 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1336 source_info->filename);
1337 assert(cache != (Cache) NULL);
1338 cache_info=(CacheInfo *) cache;
1339 assert(cache_info->signature == MagickSignature);
1340 source_info->methods=cache_info->methods;
1344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1348 + D e s t r o y I m a g e P i x e l C a c h e %
1352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1356 % The format of the DestroyImagePixelCache() method is:
1358 % void DestroyImagePixelCache(Image *image)
1360 % A description of each parameter follows:
1362 % o image: the image.
1365 static void DestroyImagePixelCache(Image *image)
1367 assert(image != (Image *) NULL);
1368 assert(image->signature == MagickSignature);
1369 if (image->debug != MagickFalse)
1370 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1371 if (image->cache == (void *) NULL)
1373 image->cache=DestroyPixelCache(image->cache);
1377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1381 + D e s t r o y I m a g e P i x e l s %
1385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1389 % The format of the DestroyImagePixels() method is:
1391 % void DestroyImagePixels(Image *image)
1393 % A description of each parameter follows:
1395 % o image: the image.
1398 MagickExport void DestroyImagePixels(Image *image)
1403 assert(image != (const Image *) NULL);
1404 assert(image->signature == MagickSignature);
1405 if (image->debug != MagickFalse)
1406 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1407 assert(image->cache != (Cache) NULL);
1408 cache_info=(CacheInfo *) image->cache;
1409 assert(cache_info->signature == MagickSignature);
1410 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1412 cache_info->methods.destroy_pixel_handler(image);
1415 image->cache=DestroyPixelCache(image->cache);
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1423 + D e s t r o y P i x e l C a c h e %
1427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1431 % The format of the DestroyPixelCache() method is:
1433 % Cache DestroyPixelCache(Cache cache)
1435 % A description of each parameter follows:
1437 % o cache: the pixel cache.
1441 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1443 switch (cache_info->type)
1447 if (cache_info->mapped == MagickFalse)
1448 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1449 cache_info->pixels);
1451 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1452 (size_t) cache_info->length);
1453 RelinquishMagickResource(MemoryResource,cache_info->length);
1458 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1459 cache_info->length);
1460 RelinquishMagickResource(MapResource,cache_info->length);
1464 if (cache_info->file != -1)
1465 (void) ClosePixelCacheOnDisk(cache_info);
1466 RelinquishMagickResource(DiskResource,cache_info->length);
1472 cache_info->type=UndefinedCache;
1473 cache_info->mapped=MagickFalse;
1474 cache_info->indexes=(IndexPacket *) NULL;
1477 MagickExport Cache DestroyPixelCache(Cache cache)
1482 assert(cache != (Cache) NULL);
1483 cache_info=(CacheInfo *) cache;
1484 assert(cache_info->signature == MagickSignature);
1485 if (cache_info->debug != MagickFalse)
1486 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1487 cache_info->filename);
1488 LockSemaphoreInfo(cache_info->semaphore);
1489 cache_info->reference_count--;
1490 if (cache_info->reference_count != 0)
1492 UnlockSemaphoreInfo(cache_info->semaphore);
1493 return((Cache) NULL);
1495 UnlockSemaphoreInfo(cache_info->semaphore);
1496 if (cache_resources != (SplayTreeInfo *) NULL)
1497 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1498 if (cache_info->debug != MagickFalse)
1501 message[MaxTextExtent];
1503 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1504 cache_info->filename);
1505 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1507 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1508 (cache_info->type != DiskCache)))
1509 RelinquishPixelCachePixels(cache_info);
1512 RelinquishPixelCachePixels(cache_info);
1513 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1515 *cache_info->cache_filename='\0';
1516 if (cache_info->nexus_info != (NexusInfo **) NULL)
1517 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1518 cache_info->number_threads);
1519 if (cache_info->random_info != (RandomInfo *) NULL)
1520 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1521 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1522 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1523 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1524 DestroySemaphoreInfo(&cache_info->semaphore);
1525 cache_info->signature=(~MagickSignature);
1526 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536 + D e s t r o y P i x e l C a c h e N e x u s %
1540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1542 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1544 % The format of the DestroyPixelCacheNexus() method is:
1546 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1547 % const size_t number_threads)
1549 % A description of each parameter follows:
1551 % o nexus_info: the nexus to destroy.
1553 % o number_threads: the number of nexus threads.
1557 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1559 if (nexus_info->mapped == MagickFalse)
1560 (void) RelinquishMagickMemory(nexus_info->cache);
1562 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1563 nexus_info->cache=(PixelPacket *) NULL;
1564 nexus_info->pixels=(PixelPacket *) NULL;
1565 nexus_info->indexes=(IndexPacket *) NULL;
1566 nexus_info->length=0;
1567 nexus_info->mapped=MagickFalse;
1570 MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1571 const size_t number_threads)
1576 assert(nexus_info != (NexusInfo **) NULL);
1577 for (i=0; i < (ssize_t) number_threads; i++)
1579 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1580 RelinquishCacheNexusPixels(nexus_info[i]);
1581 nexus_info[i]->signature=(~MagickSignature);
1582 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1584 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1593 + 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 %
1597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1599 % GetAuthenticIndexesFromCache() returns the indexes associated with the last
1600 % call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1602 % The format of the GetAuthenticIndexesFromCache() method is:
1604 % IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1606 % A description of each parameter follows:
1608 % o image: the image.
1611 static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1617 id = GetOpenMPThreadId();
1619 assert(image != (const Image *) NULL);
1620 assert(image->signature == MagickSignature);
1621 assert(image->cache != (Cache) NULL);
1622 cache_info=(CacheInfo *) image->cache;
1623 assert(cache_info->signature == MagickSignature);
1624 assert(id < (int) cache_info->number_threads);
1625 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
1629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1633 % G e t A u t h e n t i c I n d e x Q u e u e %
1637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639 % GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1640 % indexes associated with the last call to QueueAuthenticPixels() or
1641 % GetVirtualPixels(). NULL is returned if the black channel or colormap
1642 % indexes are not available.
1644 % The format of the GetAuthenticIndexQueue() method is:
1646 % IndexPacket *GetAuthenticIndexQueue(const Image *image)
1648 % A description of each parameter follows:
1650 % o image: the image.
1653 MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1659 id = GetOpenMPThreadId();
1661 assert(image != (const Image *) NULL);
1662 assert(image->signature == MagickSignature);
1663 assert(image->cache != (Cache) NULL);
1664 cache_info=(CacheInfo *) image->cache;
1665 assert(cache_info->signature == MagickSignature);
1666 if (cache_info->methods.get_authentic_indexes_from_handler !=
1667 (GetAuthenticIndexesFromHandler) NULL)
1668 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1669 assert(id < (int) cache_info->number_threads);
1670 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
1674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1678 + 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 %
1682 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1684 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1685 % disk pixel cache as defined by the geometry parameters. A pointer to the
1686 % pixels is returned if the pixels are transferred, otherwise a NULL is
1689 % The format of the GetAuthenticPixelCacheNexus() method is:
1691 % PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1692 % const ssize_t y,const size_t columns,const size_t rows,
1693 % NexusInfo *nexus_info,ExceptionInfo *exception)
1695 % A description of each parameter follows:
1697 % o image: the image.
1699 % o x,y,columns,rows: These values define the perimeter of a region of
1702 % o nexus_info: the cache nexus to return.
1704 % o exception: return any errors or warnings in this structure.
1708 static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1709 NexusInfo *nexus_info)
1714 if (cache_info->type == PingCache)
1716 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1717 nexus_info->region.x;
1718 return(nexus_info->pixels == (cache_info->pixels+offset) ? MagickTrue :
1722 MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1723 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1724 NexusInfo *nexus_info,ExceptionInfo *exception)
1733 Transfer pixels from the cache.
1735 assert(image != (Image *) NULL);
1736 assert(image->signature == MagickSignature);
1737 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1738 if (pixels == (PixelPacket *) NULL)
1739 return((PixelPacket *) NULL);
1740 cache_info=(CacheInfo *) image->cache;
1741 assert(cache_info->signature == MagickSignature);
1742 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1744 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1745 return((PixelPacket *) NULL);
1746 if (cache_info->active_index_channel != MagickFalse)
1747 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1748 return((PixelPacket *) NULL);
1753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1757 + 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 %
1761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1764 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1766 % The format of the GetAuthenticPixelsFromCache() method is:
1768 % PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1770 % A description of each parameter follows:
1772 % o image: the image.
1775 static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1781 id = GetOpenMPThreadId();
1783 assert(image != (const Image *) NULL);
1784 assert(image->signature == MagickSignature);
1785 assert(image->cache != (Cache) NULL);
1786 cache_info=(CacheInfo *) image->cache;
1787 assert(cache_info->signature == MagickSignature);
1788 assert(id < (int) cache_info->number_threads);
1789 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1793 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1797 % G e t A u t h e n t i c P i x e l Q u e u e %
1801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1803 % GetAuthenticPixelQueue() returns the authentic pixels associated with the
1804 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
1806 % The format of the GetAuthenticPixelQueue() method is:
1808 % PixelPacket *GetAuthenticPixelQueue(const Image image)
1810 % A description of each parameter follows:
1812 % o image: the image.
1815 MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1821 id = GetOpenMPThreadId();
1823 assert(image != (const Image *) NULL);
1824 assert(image->signature == MagickSignature);
1825 assert(image->cache != (Cache) NULL);
1826 cache_info=(CacheInfo *) image->cache;
1827 assert(cache_info->signature == MagickSignature);
1828 if (cache_info->methods.get_authentic_pixels_from_handler !=
1829 (GetAuthenticPixelsFromHandler) NULL)
1830 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1831 assert(id < (int) cache_info->number_threads);
1832 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1840 % G e t A u t h e n t i c P i x e l s %
1844 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1846 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1847 % region is successfully accessed, a pointer to a PixelPacket array
1848 % representing the region is returned, otherwise NULL is returned.
1850 % The returned pointer may point to a temporary working copy of the pixels
1851 % or it may point to the original pixels in memory. Performance is maximized
1852 % if the selected region is part of one row, or one or more full rows, since
1853 % then there is opportunity to access the pixels in-place (without a copy)
1854 % if the image is in memory, or in a memory-mapped file. The returned pointer
1855 % must *never* be deallocated by the user.
1857 % Pixels accessed via the returned pointer represent a simple array of type
1858 % PixelPacket. If the image type is CMYK or if the storage class is
1859 % PseduoClass, call GetAuthenticIndexQueue() after invoking
1860 % GetAuthenticPixels() to obtain the black color component or colormap indexes
1861 % (of type IndexPacket) corresponding to the region. Once the PixelPacket
1862 % (and/or IndexPacket) array has been updated, the changes must be saved back
1863 % to the underlying image using SyncAuthenticPixels() or they may be lost.
1865 % The format of the GetAuthenticPixels() method is:
1867 % PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1868 % const ssize_t y,const size_t columns,const size_t rows,
1869 % ExceptionInfo *exception)
1871 % A description of each parameter follows:
1873 % o image: the image.
1875 % o x,y,columns,rows: These values define the perimeter of a region of
1878 % o exception: return any errors or warnings in this structure.
1881 MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1882 const ssize_t y,const size_t columns,const size_t rows,
1883 ExceptionInfo *exception)
1889 id = GetOpenMPThreadId();
1891 assert(image != (Image *) NULL);
1892 assert(image->signature == MagickSignature);
1893 assert(image->cache != (Cache) NULL);
1894 cache_info=(CacheInfo *) image->cache;
1895 assert(cache_info->signature == MagickSignature);
1896 if (cache_info->methods.get_authentic_pixels_handler !=
1897 (GetAuthenticPixelsHandler) NULL)
1898 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1900 assert(id < (int) cache_info->number_threads);
1901 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1902 cache_info->nexus_info[id],exception));
1906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1910 + G e t A u t h e n t i c P i x e l s C a c h e %
1914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1916 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1917 % as defined by the geometry parameters. A pointer to the pixels is returned
1918 % if the pixels are transferred, otherwise a NULL is returned.
1920 % The format of the GetAuthenticPixelsCache() method is:
1922 % PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1923 % const ssize_t y,const size_t columns,const size_t rows,
1924 % ExceptionInfo *exception)
1926 % A description of each parameter follows:
1928 % o image: the image.
1930 % o x,y,columns,rows: These values define the perimeter of a region of
1933 % o exception: return any errors or warnings in this structure.
1936 static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1937 const ssize_t y,const size_t columns,const size_t rows,
1938 ExceptionInfo *exception)
1944 id = GetOpenMPThreadId();
1946 assert(image != (const Image *) NULL);
1947 assert(image->signature == MagickSignature);
1948 assert(image->cache != (Cache) NULL);
1949 cache_info=(CacheInfo *) image->cache;
1950 if (cache_info == (Cache) NULL)
1951 return((PixelPacket *) NULL);
1952 assert(cache_info->signature == MagickSignature);
1953 assert(id < (int) cache_info->number_threads);
1954 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1955 cache_info->nexus_info[id],exception));
1959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1963 + G e t I m a g e E x t e n t %
1967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1969 % GetImageExtent() returns the extent of the pixels associated with the
1970 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
1972 % The format of the GetImageExtent() method is:
1974 % MagickSizeType GetImageExtent(const Image *image)
1976 % A description of each parameter follows:
1978 % o image: the image.
1981 MagickExport MagickSizeType GetImageExtent(const Image *image)
1987 id = GetOpenMPThreadId();
1989 assert(image != (Image *) NULL);
1990 assert(image->signature == MagickSignature);
1991 if (image->debug != MagickFalse)
1992 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1993 assert(image->cache != (Cache) NULL);
1994 cache_info=(CacheInfo *) image->cache;
1995 assert(cache_info->signature == MagickSignature);
1996 assert(id < (int) cache_info->number_threads);
1997 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
2001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2005 + G e t I m a g e P i x e l C a c h e %
2009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2011 % GetImagePixelCache() ensures that there is only a single reference to the
2012 % pixel cache to be modified, updating the provided cache pointer to point to
2013 % a clone of the original pixel cache if necessary.
2015 % The format of the GetImagePixelCache method is:
2017 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2018 % ExceptionInfo *exception)
2020 % A description of each parameter follows:
2022 % o image: the image.
2024 % o clone: any value other than MagickFalse clones the cache pixels.
2026 % o exception: return any errors or warnings in this structure.
2029 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2035 Does the image match the pixel cache morphology?
2037 cache_info=(CacheInfo *) image->cache;
2038 if ((image->storage_class != cache_info->storage_class) ||
2039 (image->colorspace != cache_info->colorspace) ||
2040 (image->columns != cache_info->columns) ||
2041 (image->rows != cache_info->rows) ||
2042 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2043 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2044 return(MagickFalse);
2048 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2049 ExceptionInfo *exception)
2058 static MagickSizeType
2067 LockSemaphoreInfo(image->semaphore);
2068 if (cpu_throttle == 0)
2074 Set CPU throttle in milleseconds.
2076 cpu_throttle=MagickResourceInfinity;
2077 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2078 if (limit == (char *) NULL)
2079 limit=GetPolicyValue("throttle");
2080 if (limit != (char *) NULL)
2082 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2083 limit=DestroyString(limit);
2086 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2087 MagickDelay(cpu_throttle);
2088 if (time_limit == 0)
2091 Set the exire time in seconds.
2093 time_limit=GetMagickResourceLimit(TimeResource);
2094 cache_genesis=time((time_t *) NULL);
2096 if ((time_limit != MagickResourceInfinity) &&
2097 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
2098 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2099 assert(image->cache != (Cache) NULL);
2100 cache_info=(CacheInfo *) image->cache;
2101 destroy=MagickFalse;
2102 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2104 LockSemaphoreInfo(cache_info->semaphore);
2105 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2116 clone_image=(*image);
2117 clone_image.semaphore=AllocateSemaphoreInfo();
2118 clone_image.reference_count=1;
2119 clone_image.cache=ClonePixelCache(cache_info);
2120 clone_info=(CacheInfo *) clone_image.cache;
2121 status=OpenPixelCache(&clone_image,IOMode,exception);
2122 if (status != MagickFalse)
2124 if (clone != MagickFalse)
2125 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2126 if (status != MagickFalse)
2129 image->cache=clone_image.cache;
2132 DestroySemaphoreInfo(&clone_image.semaphore);
2134 UnlockSemaphoreInfo(cache_info->semaphore);
2136 if (destroy != MagickFalse)
2137 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2138 if (status != MagickFalse)
2141 Ensure the image matches the pixel cache morphology.
2143 image->taint=MagickTrue;
2144 image->type=UndefinedType;
2145 if (image->colorspace == GRAYColorspace)
2146 image->colorspace=RGBColorspace;
2147 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2148 status=OpenPixelCache(image,IOMode,exception);
2150 UnlockSemaphoreInfo(image->semaphore);
2151 if (status == MagickFalse)
2152 return((Cache) NULL);
2153 return(image->cache);
2157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2161 % G e t O n e A u t h e n t i c P i x e l %
2165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2167 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2168 % location. The image background color is returned if an error occurs.
2170 % The format of the GetOneAuthenticPixel() method is:
2172 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2173 % const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2175 % A description of each parameter follows:
2177 % o image: the image.
2179 % o x,y: These values define the location of the pixel to return.
2181 % o pixel: return a pixel at the specified (x,y) location.
2183 % o exception: return any errors or warnings in this structure.
2186 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2187 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2195 assert(image != (Image *) NULL);
2196 assert(image->signature == MagickSignature);
2197 assert(image->cache != (Cache) NULL);
2198 cache_info=(CacheInfo *) image->cache;
2199 assert(cache_info->signature == MagickSignature);
2200 *pixel=image->background_color;
2201 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2202 (GetOneAuthenticPixelFromHandler) NULL)
2203 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2205 *pixel=image->background_color;
2206 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2207 if (pixels == (PixelPacket *) NULL)
2208 return(MagickFalse);
2214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2218 + 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 %
2222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2224 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2225 % location. The image background color is returned if an error occurs.
2227 % The format of the GetOneAuthenticPixelFromCache() method is:
2229 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2230 % const ssize_t x,const ssize_t y,PixelPacket *pixel,
2231 % ExceptionInfo *exception)
2233 % A description of each parameter follows:
2235 % o image: the image.
2237 % o x,y: These values define the location of the pixel to return.
2239 % o pixel: return a pixel at the specified (x,y) location.
2241 % o exception: return any errors or warnings in this structure.
2244 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2245 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2251 id = GetOpenMPThreadId();
2256 assert(image != (const Image *) NULL);
2257 assert(image->signature == MagickSignature);
2258 assert(image->cache != (Cache) NULL);
2259 cache_info=(CacheInfo *) image->cache;
2260 assert(cache_info->signature == MagickSignature);
2261 *pixel=image->background_color;
2262 assert(id < (int) cache_info->number_threads);
2263 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2264 cache_info->nexus_info[id],exception);
2265 if (pixels == (PixelPacket *) NULL)
2266 return(MagickFalse);
2272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2276 % G e t O n e V i r t u a l M a g i c k P i x e l %
2280 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2282 % GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2283 % location. The image background color is returned if an error occurs. If
2284 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2286 % The format of the GetOneVirtualMagickPixel() method is:
2288 % MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2289 % const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2290 % ExceptionInfo exception)
2292 % A description of each parameter follows:
2294 % o image: the image.
2296 % o x,y: these values define the location of the pixel to return.
2298 % o pixel: return a pixel at the specified (x,y) location.
2300 % o exception: return any errors or warnings in this structure.
2303 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2304 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2305 ExceptionInfo *exception)
2311 id = GetOpenMPThreadId();
2313 register const IndexPacket
2316 register const PixelPacket
2319 assert(image != (const Image *) NULL);
2320 assert(image->signature == MagickSignature);
2321 assert(image->cache != (Cache) NULL);
2322 cache_info=(CacheInfo *) image->cache;
2323 assert(cache_info->signature == MagickSignature);
2324 assert(id < (int) cache_info->number_threads);
2325 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2326 1UL,1UL,cache_info->nexus_info[id],exception);
2327 GetMagickPixelPacket(image,pixel);
2328 if (pixels == (const PixelPacket *) NULL)
2329 return(MagickFalse);
2330 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
2331 SetMagickPixelPacket(image,pixels,indexes,pixel);
2336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2340 % G e t O n e V i r t u a l M e t h o d P i x e l %
2344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2346 % GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2347 % location as defined by specified pixel method. The image background color
2348 % is returned if an error occurs. If you plan to modify the pixel, use
2349 % GetOneAuthenticPixel() instead.
2351 % The format of the GetOneVirtualMethodPixel() method is:
2353 % MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2354 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2355 % const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
2357 % A description of each parameter follows:
2359 % o image: the image.
2361 % o virtual_pixel_method: the virtual pixel method.
2363 % o x,y: These values define the location of the pixel to return.
2365 % o pixel: return a pixel at the specified (x,y) location.
2367 % o exception: return any errors or warnings in this structure.
2370 MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2371 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2372 PixelPacket *pixel,ExceptionInfo *exception)
2378 id = GetOpenMPThreadId();
2383 assert(image != (const Image *) NULL);
2384 assert(image->signature == MagickSignature);
2385 assert(image->cache != (Cache) NULL);
2386 cache_info=(CacheInfo *) image->cache;
2387 assert(cache_info->signature == MagickSignature);
2388 *pixel=image->background_color;
2389 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2390 (GetOneVirtualPixelFromHandler) NULL)
2391 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2392 virtual_pixel_method,x,y,pixel,exception));
2393 assert(id < (int) cache_info->number_threads);
2394 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2395 cache_info->nexus_info[id],exception);
2396 if (pixels == (const PixelPacket *) NULL)
2397 return(MagickFalse);
2403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2407 % G e t O n e V i r t u a l P i x e l %
2411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2413 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2414 % (x,y) location. The image background color is returned if an error occurs.
2415 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2417 % The format of the GetOneVirtualPixel() method is:
2419 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2420 % const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
2422 % A description of each parameter follows:
2424 % o image: the image.
2426 % o x,y: These values define the location of the pixel to return.
2428 % o pixel: return a pixel at the specified (x,y) location.
2430 % o exception: return any errors or warnings in this structure.
2433 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2434 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2440 id = GetOpenMPThreadId();
2445 assert(image != (const Image *) NULL);
2446 assert(image->signature == MagickSignature);
2447 assert(image->cache != (Cache) NULL);
2448 cache_info=(CacheInfo *) image->cache;
2449 assert(cache_info->signature == MagickSignature);
2450 *pixel=image->background_color;
2451 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2452 (GetOneVirtualPixelFromHandler) NULL)
2453 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2454 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2455 assert(id < (int) cache_info->number_threads);
2456 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2457 1UL,1UL,cache_info->nexus_info[id],exception);
2458 if (pixels == (const PixelPacket *) NULL)
2459 return(MagickFalse);
2465 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2469 + 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 %
2473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2475 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2476 % specified (x,y) location. The image background color is returned if an
2479 % The format of the GetOneVirtualPixelFromCache() method is:
2481 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2482 % const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
2483 % PixelPacket *pixel,ExceptionInfo *exception)
2485 % A description of each parameter follows:
2487 % o image: the image.
2489 % o virtual_pixel_method: the virtual pixel method.
2491 % o x,y: These values define the location of the pixel to return.
2493 % o pixel: return a pixel at the specified (x,y) location.
2495 % o exception: return any errors or warnings in this structure.
2498 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2499 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2500 PixelPacket *pixel,ExceptionInfo *exception)
2506 id = GetOpenMPThreadId();
2511 assert(image != (const Image *) NULL);
2512 assert(image->signature == MagickSignature);
2513 assert(image->cache != (Cache) NULL);
2514 cache_info=(CacheInfo *) image->cache;
2515 assert(cache_info->signature == MagickSignature);
2516 assert(id < (int) cache_info->number_threads);
2517 *pixel=image->background_color;
2518 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2519 cache_info->nexus_info[id],exception);
2520 if (pixels == (const PixelPacket *) NULL)
2521 return(MagickFalse);
2527 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2531 + G e t P i x e l C a c h e C o l o r s p a c e %
2535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2537 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2539 % The format of the GetPixelCacheColorspace() method is:
2541 % Colorspace GetPixelCacheColorspace(Cache cache)
2543 % A description of each parameter follows:
2545 % o cache: the pixel cache.
2548 MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2553 assert(cache != (Cache) NULL);
2554 cache_info=(CacheInfo *) cache;
2555 assert(cache_info->signature == MagickSignature);
2556 if (cache_info->debug != MagickFalse)
2557 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2558 cache_info->filename);
2559 return(cache_info->colorspace);
2563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2567 + G e t P i x e l C a c h e M e t h o d s %
2571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2573 % GetPixelCacheMethods() initializes the CacheMethods structure.
2575 % The format of the GetPixelCacheMethods() method is:
2577 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2579 % A description of each parameter follows:
2581 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2584 MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2586 assert(cache_methods != (CacheMethods *) NULL);
2587 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2588 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2589 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2590 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2591 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2592 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2593 cache_methods->get_authentic_indexes_from_handler=
2594 GetAuthenticIndexesFromCache;
2595 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2596 cache_methods->get_one_authentic_pixel_from_handler=
2597 GetOneAuthenticPixelFromCache;
2598 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2599 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2600 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2608 + G e t P i x e l C a c h e N e x u s E x t e n t %
2612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2614 % GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2615 % the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2617 % The format of the GetPixelCacheNexusExtent() method is:
2619 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2620 % NexusInfo *nexus_info)
2622 % A description of each parameter follows:
2624 % o nexus_info: the nexus info.
2627 MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2628 NexusInfo *nexus_info)
2636 assert(cache != (const Cache) NULL);
2637 cache_info=(CacheInfo *) cache;
2638 assert(cache_info->signature == MagickSignature);
2639 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2641 return((MagickSizeType) cache_info->columns*cache_info->rows);
2646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2650 + 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 %
2654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2656 % GetPixelCacheNexusIndexes() returns the indexes associated with the
2657 % specified cache nexus.
2659 % The format of the GetPixelCacheNexusIndexes() method is:
2661 % IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2662 % NexusInfo *nexus_info)
2664 % A description of each parameter follows:
2666 % o cache: the pixel cache.
2668 % o nexus_info: the cache nexus to return the colormap indexes.
2671 MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2672 NexusInfo *nexus_info)
2677 assert(cache != (const Cache) NULL);
2678 cache_info=(CacheInfo *) cache;
2679 assert(cache_info->signature == MagickSignature);
2680 if (cache_info->storage_class == UndefinedClass)
2681 return((IndexPacket *) NULL);
2682 return(nexus_info->indexes);
2686 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2690 + G e t P i x e l C a c h e N e x u s P i x e l s %
2694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2696 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2699 % The format of the GetPixelCacheNexusPixels() method is:
2701 % PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2702 % NexusInfo *nexus_info)
2704 % A description of each parameter follows:
2706 % o cache: the pixel cache.
2708 % o nexus_info: the cache nexus to return the pixels.
2711 MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2712 NexusInfo *nexus_info)
2717 assert(cache != (const Cache) NULL);
2718 cache_info=(CacheInfo *) cache;
2719 assert(cache_info->signature == MagickSignature);
2720 if (cache_info->storage_class == UndefinedClass)
2721 return((PixelPacket *) NULL);
2722 return(nexus_info->pixels);
2726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2730 + G e t P i x e l C a c h e P i x e l s %
2734 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2736 % GetPixelCachePixels() returns the pixels associated with the specified image.
2738 % The format of the GetPixelCachePixels() method is:
2740 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2741 % ExceptionInfo *exception)
2743 % A description of each parameter follows:
2745 % o image: the image.
2747 % o length: the pixel cache length.
2749 % o exception: return any errors or warnings in this structure.
2752 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2753 ExceptionInfo *exception)
2758 assert(image != (const Image *) NULL);
2759 assert(image->signature == MagickSignature);
2760 assert(image->cache != (Cache) NULL);
2761 cache_info=(CacheInfo *) image->cache;
2762 assert(cache_info->signature == MagickSignature);
2764 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2765 return((void *) NULL);
2766 *length=cache_info->length;
2767 return((void *) cache_info->pixels);
2771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2775 + 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 %
2779 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2781 % GetPixelCacheStorageClass() returns the class type of the pixel cache.
2783 % The format of the GetPixelCacheStorageClass() method is:
2785 % ClassType GetPixelCacheStorageClass(Cache cache)
2787 % A description of each parameter follows:
2789 % o type: GetPixelCacheStorageClass returns DirectClass or PseudoClass.
2791 % o cache: the pixel cache.
2794 MagickExport ClassType GetPixelCacheStorageClass(const Cache cache)
2799 assert(cache != (Cache) NULL);
2800 cache_info=(CacheInfo *) cache;
2801 assert(cache_info->signature == MagickSignature);
2802 if (cache_info->debug != MagickFalse)
2803 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2804 cache_info->filename);
2805 return(cache_info->storage_class);
2809 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2813 + G e t P i x e l C a c h e T i l e S i z e %
2817 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2819 % GetPixelCacheTileSize() returns the pixel cache tile size.
2821 % The format of the GetPixelCacheTileSize() method is:
2823 % void GetPixelCacheTileSize(const Image *image,size_t *width,
2826 % A description of each parameter follows:
2828 % o image: the image.
2830 % o width: the optimize cache tile width in pixels.
2832 % o height: the optimize cache tile height in pixels.
2835 MagickExport void GetPixelCacheTileSize(const Image *image,size_t *width,
2838 assert(image != (Image *) NULL);
2839 assert(image->signature == MagickSignature);
2840 if (image->debug != MagickFalse)
2841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2842 *width=2048UL/sizeof(PixelPacket);
2843 if (GetPixelCacheType(image) == DiskCache)
2844 *width=8192UL/sizeof(PixelPacket);
2849 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2853 + G e t P i x e l C a c h e T y p e %
2857 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2859 % GetPixelCacheType() returns the pixel cache type (e.g. memory, disk, etc.).
2861 % The format of the GetPixelCacheType() method is:
2863 % CacheType GetPixelCacheType(const Image *image)
2865 % A description of each parameter follows:
2867 % o image: the image.
2870 MagickExport CacheType GetPixelCacheType(const Image *image)
2875 assert(image != (Image *) NULL);
2876 assert(image->signature == MagickSignature);
2877 assert(image->cache != (Cache) NULL);
2878 cache_info=(CacheInfo *) image->cache;
2879 assert(cache_info->signature == MagickSignature);
2880 return(cache_info->type);
2884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2888 + 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 %
2892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2894 % GetPixelCacheVirtualMethod() gets the "virtual pixels" method for the
2895 % pixel cache. A virtual pixel is any pixel access that is outside the
2896 % boundaries of the image cache.
2898 % The format of the GetPixelCacheVirtualMethod() method is:
2900 % VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2902 % A description of each parameter follows:
2904 % o image: the image.
2907 MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(const Image *image)
2912 assert(image != (Image *) NULL);
2913 assert(image->signature == MagickSignature);
2914 assert(image->cache != (Cache) NULL);
2915 cache_info=(CacheInfo *) image->cache;
2916 assert(cache_info->signature == MagickSignature);
2917 return(cache_info->virtual_pixel_method);
2921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2925 + 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 %
2929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2931 % GetVirtualIndexesFromCache() returns the indexes associated with the last
2932 % call to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
2934 % The format of the GetVirtualIndexesFromCache() method is:
2936 % IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2938 % A description of each parameter follows:
2940 % o image: the image.
2943 static const IndexPacket *GetVirtualIndexesFromCache(const Image *image)
2949 id = GetOpenMPThreadId();
2951 assert(image != (const Image *) NULL);
2952 assert(image->signature == MagickSignature);
2953 assert(image->cache != (Cache) NULL);
2954 cache_info=(CacheInfo *) image->cache;
2955 assert(cache_info->signature == MagickSignature);
2956 assert(id < (int) cache_info->number_threads);
2957 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
2961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2965 + 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 %
2969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2971 % GetVirtualIndexesFromNexus() returns the indexes associated with the
2972 % specified cache nexus.
2974 % The format of the GetVirtualIndexesFromNexus() method is:
2976 % const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2977 % NexusInfo *nexus_info)
2979 % A description of each parameter follows:
2981 % o cache: the pixel cache.
2983 % o nexus_info: the cache nexus to return the colormap indexes.
2986 MagickExport const IndexPacket *GetVirtualIndexesFromNexus(const Cache cache,
2987 NexusInfo *nexus_info)
2992 assert(cache != (Cache) NULL);
2993 cache_info=(CacheInfo *) cache;
2994 assert(cache_info->signature == MagickSignature);
2995 if (cache_info->storage_class == UndefinedClass)
2996 return((IndexPacket *) NULL);
2997 return(nexus_info->indexes);
3001 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3005 % G e t V i r t u a l I n d e x Q u e u e %
3009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3011 % GetVirtualIndexQueue() returns the virtual black channel or the
3012 % colormap indexes associated with the last call to QueueAuthenticPixels() or
3013 % GetVirtualPixels(). NULL is returned if the black channel or colormap
3014 % indexes are not available.
3016 % The format of the GetVirtualIndexQueue() method is:
3018 % const IndexPacket *GetVirtualIndexQueue(const Image *image)
3020 % A description of each parameter follows:
3022 % o image: the image.
3025 MagickExport const IndexPacket *GetVirtualIndexQueue(const Image *image)
3031 id = GetOpenMPThreadId();
3033 assert(image != (const Image *) NULL);
3034 assert(image->signature == MagickSignature);
3035 assert(image->cache != (Cache) NULL);
3036 cache_info=(CacheInfo *) image->cache;
3037 assert(cache_info->signature == MagickSignature);
3038 if (cache_info->methods.get_virtual_indexes_from_handler !=
3039 (GetVirtualIndexesFromHandler) NULL)
3040 return(cache_info->methods.get_virtual_indexes_from_handler(image));
3041 assert(id < (int) cache_info->number_threads);
3042 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]));
3046 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3050 + 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 %
3054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3056 % GetVirtualPixelsFromNexus() gets virtual pixels from the in-memory or disk
3057 % pixel cache as defined by the geometry parameters. A pointer to the pixels
3058 % is returned if the pixels are transferred, otherwise a NULL is returned.
3060 % The format of the GetVirtualPixelsFromNexus() method is:
3062 % PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3063 % const VirtualPixelMethod method,const ssize_t x,const ssize_t y,
3064 % const size_t columns,const size_t rows,NexusInfo *nexus_info,
3065 % ExceptionInfo *exception)
3067 % A description of each parameter follows:
3069 % o image: the image.
3071 % o virtual_pixel_method: the virtual pixel method.
3073 % o x,y,columns,rows: These values define the perimeter of a region of
3076 % o nexus_info: the cache nexus to acquire.
3078 % o exception: return any errors or warnings in this structure.
3085 0, 48, 12, 60, 3, 51, 15, 63,
3086 32, 16, 44, 28, 35, 19, 47, 31,
3087 8, 56, 4, 52, 11, 59, 7, 55,
3088 40, 24, 36, 20, 43, 27, 39, 23,
3089 2, 50, 14, 62, 1, 49, 13, 61,
3090 34, 18, 46, 30, 33, 17, 45, 29,
3091 10, 58, 6, 54, 9, 57, 5, 53,
3092 42, 26, 38, 22, 41, 25, 37, 21
3095 static inline ssize_t DitherX(const ssize_t x,const size_t columns)
3100 index=x+DitherMatrix[x & 0x07]-32L;
3103 if (index >= (ssize_t) columns)
3104 return((ssize_t) columns-1L);
3108 static inline ssize_t DitherY(const ssize_t y,const size_t rows)
3113 index=y+DitherMatrix[y & 0x07]-32L;
3116 if (index >= (ssize_t) rows)
3117 return((ssize_t) rows-1L);
3121 static inline ssize_t EdgeX(const ssize_t x,const size_t columns)
3125 if (x >= (ssize_t) columns)
3126 return((ssize_t) (columns-1));
3130 static inline ssize_t EdgeY(const ssize_t y,const size_t rows)
3134 if (y >= (ssize_t) rows)
3135 return((ssize_t) (rows-1));
3139 static inline ssize_t RandomX(RandomInfo *random_info,const size_t columns)
3141 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
3144 static inline ssize_t RandomY(RandomInfo *random_info,const size_t rows)
3146 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
3150 VirtualPixelModulo() computes the remainder of dividing offset by extent. It
3151 returns not only the quotient (tile the offset falls in) but also the positive
3152 remainer within that tile such that 0 <= remainder < extent. This method is
3153 essentially a ldiv() using a floored modulo division rather than the normal
3154 default truncated modulo division.
3156 static inline MagickModulo VirtualPixelModulo(const ssize_t offset,
3157 const size_t extent)
3162 modulo.quotient=offset/(ssize_t) extent;
3165 modulo.remainder=offset-modulo.quotient*(ssize_t) extent;
3169 MagickExport const PixelPacket *GetVirtualPixelsFromNexus(const Image *image,
3170 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3171 const size_t columns,const size_t rows,NexusInfo *nexus_info,
3172 ExceptionInfo *exception)
3197 register const IndexPacket
3198 *restrict virtual_indexes;
3200 register const PixelPacket
3203 register IndexPacket
3206 register PixelPacket
3216 assert(image != (const Image *) NULL);
3217 assert(image->signature == MagickSignature);
3218 assert(image->cache != (Cache) NULL);
3219 cache_info=(CacheInfo *) image->cache;
3220 assert(cache_info->signature == MagickSignature);
3221 if (cache_info->type == UndefinedCache)
3222 return((const PixelPacket *) NULL);
3225 region.width=columns;
3227 pixels=SetPixelCacheNexusPixels(image,®ion,nexus_info,exception);
3228 if (pixels == (PixelPacket *) NULL)
3229 return((const PixelPacket *) NULL);
3230 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3231 nexus_info->region.x;
3232 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3233 nexus_info->region.width-1L;
3234 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3235 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3236 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3237 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3243 Pixel request is inside cache extents.
3245 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
3247 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3248 if (status == MagickFalse)
3249 return((const PixelPacket *) NULL);
3250 if ((cache_info->storage_class == PseudoClass) ||
3251 (cache_info->colorspace == CMYKColorspace))
3253 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3254 if (status == MagickFalse)
3255 return((const PixelPacket *) NULL);
3260 Pixel request is outside cache extents.
3263 indexes=GetPixelCacheNexusIndexes(cache_info,nexus_info);
3264 virtual_nexus=AcquirePixelCacheNexus(1);
3265 if (virtual_nexus == (NexusInfo **) NULL)
3267 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3268 "UnableToGetCacheNexus","`%s'",image->filename);
3269 return((const PixelPacket *) NULL);
3271 switch (virtual_pixel_method)
3273 case BlackVirtualPixelMethod:
3275 SetRedPixelComponent(&virtual_pixel,0);
3276 SetGreenPixelComponent(&virtual_pixel,0);
3277 SetBluePixelComponent(&virtual_pixel,0);
3278 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3281 case GrayVirtualPixelMethod:
3283 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3284 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3285 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange/2);
3286 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3289 case TransparentVirtualPixelMethod:
3291 SetRedPixelComponent(&virtual_pixel,0);
3292 SetGreenPixelComponent(&virtual_pixel,0);
3293 SetBluePixelComponent(&virtual_pixel,0);
3294 SetOpacityPixelComponent(&virtual_pixel,TransparentOpacity);
3297 case MaskVirtualPixelMethod:
3298 case WhiteVirtualPixelMethod:
3300 SetRedPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3301 SetGreenPixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3302 SetBluePixelComponent(&virtual_pixel,(Quantum) QuantumRange);
3303 SetOpacityPixelComponent(&virtual_pixel,OpaqueOpacity);
3308 virtual_pixel=image->background_color;
3313 for (v=0; v < (ssize_t) rows; v++)
3315 for (u=0; u < (ssize_t) columns; u+=length)
3317 length=(MagickSizeType) MagickMin(cache_info->columns-(x+u),columns-u);
3318 if ((((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns)) ||
3319 (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows)) ||
3327 Transfer a single pixel.
3329 length=(MagickSizeType) 1;
3330 switch (virtual_pixel_method)
3332 case BackgroundVirtualPixelMethod:
3333 case ConstantVirtualPixelMethod:
3334 case BlackVirtualPixelMethod:
3335 case GrayVirtualPixelMethod:
3336 case TransparentVirtualPixelMethod:
3337 case MaskVirtualPixelMethod:
3338 case WhiteVirtualPixelMethod:
3341 virtual_indexes=(&virtual_index);
3344 case EdgeVirtualPixelMethod:
3347 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3348 EdgeX(x+u,cache_info->columns),EdgeY(y+v,cache_info->rows),
3349 1UL,1UL,*virtual_nexus,exception);
3350 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3354 case RandomVirtualPixelMethod:
3356 if (cache_info->random_info == (RandomInfo *) NULL)
3357 cache_info->random_info=AcquireRandomInfo();
3358 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3359 RandomX(cache_info->random_info,cache_info->columns),
3360 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3361 *virtual_nexus,exception);
3362 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3366 case DitherVirtualPixelMethod:
3368 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3369 DitherX(x+u,cache_info->columns),DitherY(y+v,cache_info->rows),
3370 1UL,1UL,*virtual_nexus,exception);
3371 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3375 case TileVirtualPixelMethod:
3377 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3378 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3379 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3380 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3382 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3386 case MirrorVirtualPixelMethod:
3388 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3389 if ((x_modulo.quotient & 0x01) == 1L)
3390 x_modulo.remainder=(ssize_t) cache_info->columns-
3391 x_modulo.remainder-1L;
3392 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3393 if ((y_modulo.quotient & 0x01) == 1L)
3394 y_modulo.remainder=(ssize_t) cache_info->rows-
3395 y_modulo.remainder-1L;
3396 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3397 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3399 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3403 case CheckerTileVirtualPixelMethod:
3405 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3406 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3407 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3410 virtual_indexes=(&virtual_index);
3413 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3414 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3416 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3420 case HorizontalTileVirtualPixelMethod:
3422 if (((y+v) < 0) || ((y+v) >= (ssize_t) cache_info->rows))
3425 virtual_indexes=(&virtual_index);
3428 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3429 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3430 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3431 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3433 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3437 case VerticalTileVirtualPixelMethod:
3439 if (((x+u) < 0) || ((x+u) >= (ssize_t) cache_info->columns))
3442 virtual_indexes=(&virtual_index);
3445 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3446 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3447 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3448 x_modulo.remainder,y_modulo.remainder,1UL,1UL,*virtual_nexus,
3450 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3454 case HorizontalTileEdgeVirtualPixelMethod:
3456 x_modulo=VirtualPixelModulo(x+u,cache_info->columns);
3457 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3458 x_modulo.remainder,EdgeY(y+v,cache_info->rows),1UL,1UL,
3459 *virtual_nexus,exception);
3460 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3464 case VerticalTileEdgeVirtualPixelMethod:
3466 y_modulo=VirtualPixelModulo(y+v,cache_info->rows);
3467 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,
3468 EdgeX(x+u,cache_info->columns),y_modulo.remainder,1UL,1UL,
3469 *virtual_nexus,exception);
3470 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3475 if (p == (const PixelPacket *) NULL)
3478 if ((indexes != (IndexPacket *) NULL) &&
3479 (virtual_indexes != (const IndexPacket *) NULL))
3480 *indexes++=(*virtual_indexes);
3484 Transfer a run of pixels.
3486 p=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x+u,y+v,
3487 (size_t) length,1UL,*virtual_nexus,exception);
3488 if (p == (const PixelPacket *) NULL)
3490 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,*virtual_nexus);
3491 (void) memcpy(q,p,(size_t) length*sizeof(*p));
3493 if ((indexes != (IndexPacket *) NULL) &&
3494 (virtual_indexes != (const IndexPacket *) NULL))
3496 (void) memcpy(indexes,virtual_indexes,(size_t) length*
3497 sizeof(*virtual_indexes));
3502 virtual_nexus=DestroyPixelCacheNexus(virtual_nexus,1);
3507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3511 + G e t V i r t u a l P i x e l C a c h e %
3515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3517 % GetVirtualPixelCache() get virtual pixels from the in-memory or disk pixel
3518 % cache as defined by the geometry parameters. A pointer to the pixels
3519 % is returned if the pixels are transferred, otherwise a NULL is returned.
3521 % The format of the GetVirtualPixelCache() method is:
3523 % const PixelPacket *GetVirtualPixelCache(const Image *image,
3524 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
3525 % const ssize_t y,const size_t columns,const size_t rows,
3526 % ExceptionInfo *exception)
3528 % A description of each parameter follows:
3530 % o image: the image.
3532 % o virtual_pixel_method: the virtual pixel method.
3534 % o x,y,columns,rows: These values define the perimeter of a region of
3537 % o exception: return any errors or warnings in this structure.
3540 static const PixelPacket *GetVirtualPixelCache(const Image *image,
3541 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
3542 const size_t columns,const size_t rows,ExceptionInfo *exception)
3548 id = GetOpenMPThreadId();
3550 assert(image != (const Image *) NULL);
3551 assert(image->signature == MagickSignature);
3552 assert(image->cache != (Cache) NULL);
3553 cache_info=(CacheInfo *) image->cache;
3554 assert(cache_info->signature == MagickSignature);
3555 assert(id < (int) cache_info->number_threads);
3556 return(GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,columns,rows,
3557 cache_info->nexus_info[id],exception));
3561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3565 % G e t V i r t u a l P i x e l Q u e u e %
3569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3571 % GetVirtualPixelQueue() returns the virtual pixels associated with the
3572 % last call to QueueAuthenticPixels() or GetVirtualPixels().
3574 % The format of the GetVirtualPixelQueue() method is:
3576 % const PixelPacket *GetVirtualPixelQueue(const Image image)
3578 % A description of each parameter follows:
3580 % o image: the image.
3583 MagickExport const PixelPacket *GetVirtualPixelQueue(const Image *image)
3589 id = GetOpenMPThreadId();
3591 assert(image != (const Image *) NULL);
3592 assert(image->signature == MagickSignature);
3593 assert(image->cache != (Cache) NULL);
3594 cache_info=(CacheInfo *) image->cache;
3595 assert(cache_info->signature == MagickSignature);
3596 if (cache_info->methods.get_virtual_pixels_handler !=
3597 (GetVirtualPixelsHandler) NULL)
3598 return(cache_info->methods.get_virtual_pixels_handler(image));
3599 assert(id < (int) cache_info->number_threads);
3600 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[id]));
3604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3608 % G e t V i r t u a l P i x e l s %
3612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3614 % GetVirtualPixels() returns an immutable pixel region. If the
3615 % region is successfully accessed, a pointer to it is returned, otherwise
3616 % NULL is returned. The returned pointer may point to a temporary working
3617 % copy of the pixels or it may point to the original pixels in memory.
3618 % Performance is maximized if the selected region is part of one row, or one
3619 % or more full rows, since there is opportunity to access the pixels in-place
3620 % (without a copy) if the image is in memory, or in a memory-mapped file. The
3621 % returned pointer must *never* be deallocated by the user.
3623 % Pixels accessed via the returned pointer represent a simple array of type
3624 % PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
3625 % call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to access
3626 % the black color component or to obtain the colormap indexes (of type
3627 % IndexPacket) corresponding to the region.
3629 % If you plan to modify the pixels, use GetAuthenticPixels() instead.
3631 % Note, the GetVirtualPixels() and GetAuthenticPixels() methods are not thread-
3632 % safe. In a threaded environment, use GetCacheViewVirtualPixels() or
3633 % GetCacheViewAuthenticPixels() instead.
3635 % The format of the GetVirtualPixels() method is:
3637 % const PixelPacket *GetVirtualPixels(const Image *image,const ssize_t x,
3638 % const ssize_t y,const size_t columns,const size_t rows,
3639 % ExceptionInfo *exception)
3641 % A description of each parameter follows:
3643 % o image: the image.
3645 % o x,y,columns,rows: These values define the perimeter of a region of
3648 % o exception: return any errors or warnings in this structure.
3651 MagickExport const PixelPacket *GetVirtualPixels(const Image *image,
3652 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
3653 ExceptionInfo *exception)
3659 id = GetOpenMPThreadId();
3661 assert(image != (const Image *) NULL);
3662 assert(image->signature == MagickSignature);
3663 assert(image->cache != (Cache) NULL);
3664 cache_info=(CacheInfo *) image->cache;
3665 assert(cache_info->signature == MagickSignature);
3666 if (cache_info->methods.get_virtual_pixel_handler !=
3667 (GetVirtualPixelHandler) NULL)
3668 return(cache_info->methods.get_virtual_pixel_handler(image,
3669 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3670 assert(id < (int) cache_info->number_threads);
3671 return(GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3672 columns,rows,cache_info->nexus_info[id],exception));
3676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3680 + 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 %
3684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3686 % GetVirtualPixelsCache() returns the pixels associated with the last call
3687 % to QueueAuthenticPixelsCache() or GetVirtualPixelCache().
3689 % The format of the GetVirtualPixelsCache() method is:
3691 % PixelPacket *GetVirtualPixelsCache(const Image *image)
3693 % A description of each parameter follows:
3695 % o image: the image.
3698 static const PixelPacket *GetVirtualPixelsCache(const Image *image)
3704 id = GetOpenMPThreadId();
3706 assert(image != (const Image *) NULL);
3707 assert(image->signature == MagickSignature);
3708 assert(image->cache != (Cache) NULL);
3709 cache_info=(CacheInfo *) image->cache;
3710 assert(cache_info->signature == MagickSignature);
3711 assert(id < (int) cache_info->number_threads);
3712 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[id]));
3716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3720 + G e t V i r t u a l P i x e l s N e x u s %
3724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3726 % GetVirtualPixelsNexus() returns the pixels associated with the specified
3729 % The format of the GetVirtualPixelsNexus() method is:
3731 % const IndexPacket *GetVirtualPixelsNexus(const Cache cache,
3732 % NexusInfo *nexus_info)
3734 % A description of each parameter follows:
3736 % o cache: the pixel cache.
3738 % o nexus_info: the cache nexus to return the colormap pixels.
3741 MagickExport const PixelPacket *GetVirtualPixelsNexus(const Cache cache,
3742 NexusInfo *nexus_info)
3747 assert(cache != (Cache) NULL);
3748 cache_info=(CacheInfo *) cache;
3749 assert(cache_info->signature == MagickSignature);
3750 if (cache_info->storage_class == UndefinedClass)
3751 return((PixelPacket *) NULL);
3752 return((const PixelPacket *) nexus_info->pixels);
3756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3760 + M a s k P i x e l C a c h e N e x u s %
3764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3766 % MaskPixelCacheNexus() masks the cache nexus as defined by the image mask.
3767 % The method returns MagickTrue if the pixel region is masked, otherwise
3770 % The format of the MaskPixelCacheNexus() method is:
3772 % MagickBooleanType MaskPixelCacheNexus(Image *image,
3773 % NexusInfo *nexus_info,ExceptionInfo *exception)
3775 % A description of each parameter follows:
3777 % o image: the image.
3779 % o nexus_info: the cache nexus to clip.
3781 % o exception: return any errors or warnings in this structure.
3785 static inline void MagickPixelCompositeMask(const MagickPixelPacket *p,
3786 const MagickRealType alpha,const MagickPixelPacket *q,
3787 const MagickRealType beta,MagickPixelPacket *composite)
3792 if (alpha == TransparentOpacity)
3797 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3798 gamma=1.0/(gamma <= MagickEpsilon ? 1.0 : gamma);
3799 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3800 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3801 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3802 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3803 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3806 static MagickBooleanType MaskPixelCacheNexus(Image *image,NexusInfo *nexus_info,
3807 ExceptionInfo *exception)
3823 register const PixelPacket
3826 register IndexPacket
3827 *restrict nexus_indexes,
3830 register PixelPacket
3840 if (image->debug != MagickFalse)
3841 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3842 if (image->mask == (Image *) NULL)
3843 return(MagickFalse);
3844 cache_info=(CacheInfo *) image->cache;
3845 if (cache_info == (Cache) NULL)
3846 return(MagickFalse);
3847 image_nexus=AcquirePixelCacheNexus(1);
3848 clip_nexus=AcquirePixelCacheNexus(1);
3849 if ((image_nexus == (NexusInfo **) NULL) ||
3850 (clip_nexus == (NexusInfo **) NULL))
3851 ThrowBinaryException(CacheError,"UnableToGetCacheNexus",image->filename);
3852 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,
3853 nexus_info->region.y,nexus_info->region.width,nexus_info->region.height,
3854 image_nexus[0],exception);
3855 indexes=GetPixelCacheNexusIndexes(image->cache,image_nexus[0]);
3856 q=nexus_info->pixels;
3857 nexus_indexes=nexus_info->indexes;
3858 r=GetVirtualPixelsFromNexus(image->mask,MaskVirtualPixelMethod,
3859 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3860 nexus_info->region.height,clip_nexus[0],&image->exception);
3861 GetMagickPixelPacket(image,&alpha);
3862 GetMagickPixelPacket(image,&beta);
3863 number_pixels=(MagickSizeType) nexus_info->region.width*
3864 nexus_info->region.height;
3865 for (i=0; i < (ssize_t) number_pixels; i++)
3867 if ((p == (PixelPacket *) NULL) || (r == (const PixelPacket *) NULL))
3869 SetMagickPixelPacket(image,p,indexes+i,&alpha);
3870 SetMagickPixelPacket(image,q,nexus_indexes+i,&beta);
3871 MagickPixelCompositeMask(&beta,(MagickRealType) PixelIntensityToQuantum(r),
3872 &alpha,alpha.opacity,&beta);
3873 q->red=ClampToQuantum(beta.red);
3874 q->green=ClampToQuantum(beta.green);
3875 q->blue=ClampToQuantum(beta.blue);
3876 q->opacity=ClampToQuantum(beta.opacity);
3877 if (cache_info->active_index_channel != MagickFalse)
3878 nexus_indexes[i]=indexes[i];
3883 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
3884 image_nexus=DestroyPixelCacheNexus(image_nexus,1);
3885 if (i < (ssize_t) number_pixels)
3886 return(MagickFalse);
3891 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3895 + O p e n P i x e l C a c h e %
3899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3901 % OpenPixelCache() allocates the pixel cache. This includes defining the cache
3902 % dimensions, allocating space for the image pixels and optionally the
3903 % colormap indexes, and memory mapping the cache if it is disk based. The
3904 % cache nexus array is initialized as well.
3906 % The format of the OpenPixelCache() method is:
3908 % MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3909 % ExceptionInfo *exception)
3911 % A description of each parameter follows:
3913 % o image: the image.
3915 % o mode: ReadMode, WriteMode, or IOMode.
3917 % o exception: return any errors or warnings in this structure.
3921 static inline void AllocatePixelCachePixels(CacheInfo *cache_info)
3923 cache_info->mapped=MagickFalse;
3924 cache_info->pixels=(PixelPacket *) AcquireMagickMemory((size_t)
3925 cache_info->length);
3926 if (cache_info->pixels == (PixelPacket *) NULL)
3928 cache_info->mapped=MagickTrue;
3929 cache_info->pixels=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
3930 cache_info->length);
3934 static MagickBooleanType ExtendCache(Image *image,MagickSizeType length)
3944 cache_info=(CacheInfo *) image->cache;
3945 if (image->debug != MagickFalse)
3948 format[MaxTextExtent],
3949 message[MaxTextExtent];
3951 (void) FormatMagickSize(length,MagickFalse,format);
3952 (void) FormatMagickString(message,MaxTextExtent,
3953 "extend %s (%s[%d], disk, %sB)",cache_info->filename,
3954 cache_info->cache_filename,cache_info->file,format);
3955 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
3957 if (length != (MagickSizeType) ((MagickOffsetType) length))
3958 return(MagickFalse);
3959 extent=(MagickOffsetType) MagickSeek(cache_info->file,0,SEEK_END);
3961 return(MagickFalse);
3962 if ((MagickSizeType) extent >= length)
3964 offset=(MagickOffsetType) length-1;
3965 count=WritePixelCacheRegion(cache_info,offset,1,(const unsigned char *) "");
3966 return(count == (MagickOffsetType) 1 ? MagickTrue : MagickFalse);
3969 static MagickBooleanType OpenPixelCache(Image *image,const MapMode mode,
3970 ExceptionInfo *exception)
3973 format[MaxTextExtent],
3974 message[MaxTextExtent];
3991 assert(image != (const Image *) NULL);
3992 assert(image->signature == MagickSignature);
3993 assert(image->cache != (Cache) NULL);
3994 if (image->debug != MagickFalse)
3995 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3996 if ((image->columns == 0) || (image->rows == 0))
3997 ThrowBinaryException(CacheError,"NoPixelsDefinedInCache",image->filename);
3998 cache_info=(CacheInfo *) image->cache;
3999 assert(cache_info->signature == MagickSignature);
4000 source_info=(*cache_info);
4001 source_info.file=(-1);
4002 (void) FormatMagickString(cache_info->filename,MaxTextExtent,"%s[%.20g]",
4003 image->filename,(double) GetImageIndexInList(image));
4004 cache_info->mode=mode;
4005 cache_info->rows=image->rows;
4006 cache_info->columns=image->columns;
4007 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
4008 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
4009 if (image->ping != MagickFalse)
4011 cache_info->storage_class=image->storage_class;
4012 cache_info->colorspace=image->colorspace;
4013 cache_info->type=PingCache;
4014 cache_info->pixels=(PixelPacket *) NULL;
4015 cache_info->indexes=(IndexPacket *) NULL;
4016 cache_info->length=0;
4019 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4020 packet_size=sizeof(PixelPacket);
4021 if (cache_info->active_index_channel != MagickFalse)
4022 packet_size+=sizeof(IndexPacket);
4023 length=number_pixels*packet_size;
4024 columns=(size_t) (length/cache_info->rows/packet_size);
4025 if (cache_info->columns != columns)
4026 ThrowBinaryException(ResourceLimitError,"PixelCacheAllocationFailed",
4028 cache_info->length=length;
4029 status=AcquireMagickResource(AreaResource,cache_info->length);
4030 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4031 if ((status != MagickFalse) && (length == (MagickSizeType) ((size_t) length)))
4033 status=AcquireMagickResource(MemoryResource,cache_info->length);
4034 if (((cache_info->type == UndefinedCache) && (status != MagickFalse)) ||
4035 (cache_info->type == MemoryCache))
4037 AllocatePixelCachePixels(cache_info);
4038 if (cache_info->pixels == (PixelPacket *) NULL)
4039 cache_info->pixels=source_info.pixels;
4043 Create memory pixel cache.
4045 if (image->debug != MagickFalse)
4047 (void) FormatMagickSize(cache_info->length,MagickTrue,
4049 (void) FormatMagickString(message,MaxTextExtent,
4050 "open %s (%s memory, %.20gx%.20g %sB)",cache_info->filename,
4051 cache_info->mapped != MagickFalse ? "anonymous" : "heap",
4052 (double) cache_info->columns,(double) cache_info->rows,
4054 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4057 cache_info->storage_class=image->storage_class;
4058 cache_info->colorspace=image->colorspace;
4059 cache_info->type=MemoryCache;
4060 cache_info->indexes=(IndexPacket *) NULL;
4061 if (cache_info->active_index_channel != MagickFalse)
4062 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4064 if (source_info.storage_class != UndefinedClass)
4066 status|=ClonePixelCachePixels(cache_info,&source_info,
4068 RelinquishPixelCachePixels(&source_info);
4073 RelinquishMagickResource(MemoryResource,cache_info->length);
4076 Create pixel cache on disk.
4078 status=AcquireMagickResource(DiskResource,cache_info->length);
4079 if (status == MagickFalse)
4081 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4082 "CacheResourcesExhausted","`%s'",image->filename);
4083 return(MagickFalse);
4085 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4087 RelinquishMagickResource(DiskResource,cache_info->length);
4088 ThrowFileException(exception,CacheError,"UnableToOpenPixelCache",
4090 return(MagickFalse);
4092 status=ExtendCache(image,(MagickSizeType) cache_info->offset+
4093 cache_info->length);
4094 if (status == MagickFalse)
4096 ThrowFileException(exception,CacheError,"UnableToExtendCache",
4098 return(MagickFalse);
4100 cache_info->storage_class=image->storage_class;
4101 cache_info->colorspace=image->colorspace;
4102 length=number_pixels*(sizeof(PixelPacket)+sizeof(IndexPacket));
4103 status=AcquireMagickResource(AreaResource,cache_info->length);
4104 if ((status == MagickFalse) || (length != (MagickSizeType) ((size_t) length)))
4105 cache_info->type=DiskCache;
4108 status=AcquireMagickResource(MapResource,cache_info->length);
4109 if ((status == MagickFalse) && (cache_info->type != MapCache) &&
4110 (cache_info->type != MemoryCache))
4111 cache_info->type=DiskCache;
4114 cache_info->pixels=(PixelPacket *) MapBlob(cache_info->file,mode,
4115 cache_info->offset,(size_t) cache_info->length);
4116 if (cache_info->pixels == (PixelPacket *) NULL)
4118 cache_info->pixels=source_info.pixels;
4119 cache_info->type=DiskCache;
4124 Create file-backed memory-mapped pixel cache.
4126 (void) ClosePixelCacheOnDisk(cache_info);
4127 cache_info->type=MapCache;
4128 cache_info->mapped=MagickTrue;
4129 cache_info->indexes=(IndexPacket *) NULL;
4130 if (cache_info->active_index_channel != MagickFalse)
4131 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4133 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4135 status=ClonePixelCachePixels(cache_info,&source_info,
4137 RelinquishPixelCachePixels(&source_info);
4139 if (image->debug != MagickFalse)
4141 (void) FormatMagickSize(cache_info->length,MagickTrue,
4143 (void) FormatMagickString(message,MaxTextExtent,
4144 "open %s (%s[%d], memory-mapped, %.20gx%.20g %sB)",
4145 cache_info->filename,cache_info->cache_filename,
4146 cache_info->file,(double) cache_info->columns,(double)
4147 cache_info->rows,format);
4148 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
4154 RelinquishMagickResource(MapResource,cache_info->length);
4156 if ((source_info.type != UndefinedCache) && (mode != ReadMode))
4158 status=ClonePixelCachePixels(cache_info,&source_info,exception);
4159 RelinquishPixelCachePixels(&source_info);
4161 if (image->debug != MagickFalse)
4163 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4164 (void) FormatMagickString(message,MaxTextExtent,
4165 "open %s (%s[%d], disk, %.20gx%.20g %sB)",cache_info->filename,
4166 cache_info->cache_filename,cache_info->file,(double)
4167 cache_info->columns,(double) cache_info->rows,format);
4168 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
4174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4178 + P e r s i s t P i x e l C a c h e %
4182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4184 % PersistPixelCache() attaches to or initializes a persistent pixel cache. A
4185 % persistent pixel cache is one that resides on disk and is not destroyed
4186 % when the program exits.
4188 % The format of the PersistPixelCache() method is:
4190 % MagickBooleanType PersistPixelCache(Image *image,const char *filename,
4191 % const MagickBooleanType attach,MagickOffsetType *offset,
4192 % ExceptionInfo *exception)
4194 % A description of each parameter follows:
4196 % o image: the image.
4198 % o filename: the persistent pixel cache filename.
4200 % o attach: A value other than zero initializes the persistent pixel
4203 % o initialize: A value other than zero initializes the persistent pixel
4206 % o offset: the offset in the persistent cache to store pixels.
4208 % o exception: return any errors or warnings in this structure.
4211 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4212 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4213 ExceptionInfo *exception)
4228 assert(image != (Image *) NULL);
4229 assert(image->signature == MagickSignature);
4230 if (image->debug != MagickFalse)
4231 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4232 assert(image->cache != (void *) NULL);
4233 assert(filename != (const char *) NULL);
4234 assert(offset != (MagickOffsetType *) NULL);
4235 page_size=GetMagickPageSize();
4236 cache_info=(CacheInfo *) image->cache;
4237 assert(cache_info->signature == MagickSignature);
4238 if (attach != MagickFalse)
4241 Attach existing persistent pixel cache.
4243 if (image->debug != MagickFalse)
4244 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4245 "attach persistent cache");
4246 (void) CopyMagickString(cache_info->cache_filename,filename,
4248 cache_info->type=DiskCache;
4249 cache_info->offset=(*offset);
4250 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4251 return(MagickFalse);
4252 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4255 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4256 (cache_info->reference_count == 1))
4258 LockSemaphoreInfo(cache_info->semaphore);
4259 if ((cache_info->mode != ReadMode) &&
4260 (cache_info->type != MemoryCache) &&
4261 (cache_info->reference_count == 1))
4267 Usurp existing persistent pixel cache.
4269 status=rename(cache_info->cache_filename,filename);
4272 (void) CopyMagickString(cache_info->cache_filename,filename,
4274 *offset+=cache_info->length+page_size-(cache_info->length %
4276 UnlockSemaphoreInfo(cache_info->semaphore);
4277 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4278 if (image->debug != MagickFalse)
4279 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4280 "Usurp resident persistent cache");
4284 UnlockSemaphoreInfo(cache_info->semaphore);
4287 Clone persistent pixel cache.
4289 clone_image=(*image);
4290 clone_info=(CacheInfo *) clone_image.cache;
4291 image->cache=ClonePixelCache(cache_info);
4292 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4293 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4294 cache_info->type=DiskCache;
4295 cache_info->offset=(*offset);
4296 cache_info=(CacheInfo *) image->cache;
4297 status=OpenPixelCache(image,IOMode,exception);
4298 if (status != MagickFalse)
4299 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4300 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4301 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4310 + Q u e u e A u t h e n t i c N e x u s %
4314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4316 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4317 % by the region rectangle and returns a pointer to the region. This region is
4318 % subsequently transferred from the pixel cache with
4319 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4320 % pixels are transferred, otherwise a NULL is returned.
4322 % The format of the QueueAuthenticNexus() method is:
4324 % PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4325 % const ssize_t y,const size_t columns,const size_t rows,
4326 % NexusInfo *nexus_info,ExceptionInfo *exception)
4328 % A description of each parameter follows:
4330 % o image: the image.
4332 % o x,y,columns,rows: These values define the perimeter of a region of
4335 % o nexus_info: the cache nexus to set.
4337 % o exception: return any errors or warnings in this structure.
4340 MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4341 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4342 ExceptionInfo *exception)
4357 Validate pixel cache geometry.
4359 assert(image != (const Image *) NULL);
4360 assert(image->signature == MagickSignature);
4361 assert(image->cache != (Cache) NULL);
4362 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4363 assert(cache_info->signature == MagickSignature);
4364 if (cache_info == (Cache) NULL)
4365 return((PixelPacket *) NULL);
4366 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4368 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4369 "NoPixelsDefinedInCache","`%s'",image->filename);
4370 return((PixelPacket *) NULL);
4372 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4373 (y >= (ssize_t) cache_info->rows))
4375 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4376 "PixelsAreNotAuthentic","`%s'",image->filename);
4377 return((PixelPacket *) NULL);
4379 offset=(MagickOffsetType) y*cache_info->columns+x;
4381 return((PixelPacket *) NULL);
4382 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4383 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4384 if ((MagickSizeType) offset >= number_pixels)
4385 return((PixelPacket *) NULL);
4391 region.width=columns;
4393 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4401 + 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 %
4405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4407 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4408 % defined by the region rectangle and returns a pointer to the region. This
4409 % region is subsequently transferred from the pixel cache with
4410 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4411 % pixels are transferred, otherwise a NULL is returned.
4413 % The format of the QueueAuthenticPixelsCache() method is:
4415 % PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4416 % const ssize_t y,const size_t columns,const size_t rows,
4417 % ExceptionInfo *exception)
4419 % A description of each parameter follows:
4421 % o image: the image.
4423 % o x,y,columns,rows: These values define the perimeter of a region of
4426 % o exception: return any errors or warnings in this structure.
4429 static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4430 const ssize_t y,const size_t columns,const size_t rows,
4431 ExceptionInfo *exception)
4437 id = GetOpenMPThreadId();
4439 assert(image != (const Image *) NULL);
4440 assert(image->signature == MagickSignature);
4441 assert(image->cache != (Cache) NULL);
4442 cache_info=(CacheInfo *) image->cache;
4443 assert(cache_info->signature == MagickSignature);
4444 assert(id < (int) cache_info->number_threads);
4445 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4454 % Q u e u e A u t h e n t i c P i x e l s %
4458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4460 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4461 % successfully intialized a pointer to a PixelPacket array representing the
4462 % region is returned, otherwise NULL is returned. The returned pointer may
4463 % point to a temporary working buffer for the pixels or it may point to the
4464 % final location of the pixels in memory.
4466 % Write-only access means that any existing pixel values corresponding to
4467 % the region are ignored. This is useful if the initial image is being
4468 % created from scratch, or if the existing pixel values are to be
4469 % completely replaced without need to refer to their pre-existing values.
4470 % The application is free to read and write the pixel buffer returned by
4471 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4472 % initialize the pixel array values. Initializing pixel array values is the
4473 % application's responsibility.
4475 % Performance is maximized if the selected region is part of one row, or
4476 % one or more full rows, since then there is opportunity to access the
4477 % pixels in-place (without a copy) if the image is in memory, or in a
4478 % memory-mapped file. The returned pointer must *never* be deallocated
4481 % Pixels accessed via the returned pointer represent a simple array of type
4482 % PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4483 % call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4484 % the black color component or the colormap indexes (of type IndexPacket)
4485 % corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4486 % array has been updated, the changes must be saved back to the underlying
4487 % image using SyncAuthenticPixels() or they may be lost.
4489 % The format of the QueueAuthenticPixels() method is:
4491 % PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4492 % const ssize_t y,const size_t columns,const size_t rows,
4493 % ExceptionInfo *exception)
4495 % A description of each parameter follows:
4497 % o image: the image.
4499 % o x,y,columns,rows: These values define the perimeter of a region of
4502 % o exception: return any errors or warnings in this structure.
4505 MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4506 const ssize_t y,const size_t columns,const size_t rows,
4507 ExceptionInfo *exception)
4513 id = GetOpenMPThreadId();
4515 assert(image != (Image *) NULL);
4516 assert(image->signature == MagickSignature);
4517 assert(image->cache != (Cache) NULL);
4518 cache_info=(CacheInfo *) image->cache;
4519 assert(cache_info->signature == MagickSignature);
4520 if (cache_info->methods.queue_authentic_pixels_handler !=
4521 (QueueAuthenticPixelsHandler) NULL)
4522 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4524 assert(id < (int) cache_info->number_threads);
4525 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4534 + R e a d P i x e l C a c h e I n d e x e s %
4538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4540 % ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4543 % The format of the ReadPixelCacheIndexes() method is:
4545 % MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4546 % NexusInfo *nexus_info,ExceptionInfo *exception)
4548 % A description of each parameter follows:
4550 % o cache_info: the pixel cache.
4552 % o nexus_info: the cache nexus to read the colormap indexes.
4554 % o exception: return any errors or warnings in this structure.
4557 static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4558 NexusInfo *nexus_info,ExceptionInfo *exception)
4568 register IndexPacket
4577 if (cache_info->active_index_channel == MagickFalse)
4578 return(MagickFalse);
4579 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4581 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4582 nexus_info->region.x;
4583 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4584 rows=nexus_info->region.height;
4586 q=nexus_info->indexes;
4587 switch (cache_info->type)
4592 register IndexPacket
4596 Read indexes from memory.
4598 if ((cache_info->columns == nexus_info->region.width) &&
4599 (extent == (MagickSizeType) ((size_t) extent)))
4604 p=cache_info->indexes+offset;
4605 for (y=0; y < (ssize_t) rows; y++)
4607 (void) memcpy(q,p,(size_t) length);
4608 p+=cache_info->columns;
4609 q+=nexus_info->region.width;
4616 Read indexes from disk.
4618 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4620 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4621 cache_info->cache_filename);
4622 return(MagickFalse);
4624 if ((cache_info->columns == nexus_info->region.width) &&
4625 (extent <= MagickMaxBufferExtent))
4630 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4631 for (y=0; y < (ssize_t) rows; y++)
4633 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4634 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4635 if ((MagickSizeType) count < length)
4637 offset+=cache_info->columns;
4638 q+=nexus_info->region.width;
4640 if (y < (ssize_t) rows)
4642 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4643 cache_info->cache_filename);
4644 return(MagickFalse);
4651 if ((cache_info->debug != MagickFalse) &&
4652 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4653 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4654 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4655 nexus_info->region.width,(double) nexus_info->region.height,(double)
4656 nexus_info->region.x,(double) nexus_info->region.y);
4661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4665 + R e a d P i x e l C a c h e P i x e l s %
4669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4671 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4674 % The format of the ReadPixelCachePixels() method is:
4676 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4677 % NexusInfo *nexus_info,ExceptionInfo *exception)
4679 % A description of each parameter follows:
4681 % o cache_info: the pixel cache.
4683 % o nexus_info: the cache nexus to read the pixels.
4685 % o exception: return any errors or warnings in this structure.
4688 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4689 NexusInfo *nexus_info,ExceptionInfo *exception)
4699 register PixelPacket
4708 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4710 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4711 nexus_info->region.x;
4712 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4713 rows=nexus_info->region.height;
4715 q=nexus_info->pixels;
4716 switch (cache_info->type)
4721 register PixelPacket
4725 Read pixels from memory.
4727 if ((cache_info->columns == nexus_info->region.width) &&
4728 (extent == (MagickSizeType) ((size_t) extent)))
4733 p=cache_info->pixels+offset;
4734 for (y=0; y < (ssize_t) rows; y++)
4736 (void) memcpy(q,p,(size_t) length);
4737 p+=cache_info->columns;
4738 q+=nexus_info->region.width;
4745 Read pixels from disk.
4747 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4749 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4750 cache_info->cache_filename);
4751 return(MagickFalse);
4753 if ((cache_info->columns == nexus_info->region.width) &&
4754 (extent <= MagickMaxBufferExtent))
4759 for (y=0; y < (ssize_t) rows; y++)
4761 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4762 sizeof(*q),length,(unsigned char *) q);
4763 if ((MagickSizeType) count < length)
4765 offset+=cache_info->columns;
4766 q+=nexus_info->region.width;
4768 if (y < (ssize_t) rows)
4770 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4771 cache_info->cache_filename);
4772 return(MagickFalse);
4779 if ((cache_info->debug != MagickFalse) &&
4780 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4781 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4782 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4783 nexus_info->region.width,(double) nexus_info->region.height,(double)
4784 nexus_info->region.x,(double) nexus_info->region.y);
4789 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4793 + R e f e r e n c e P i x e l C a c h e %
4797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4799 % ReferencePixelCache() increments the reference count associated with the
4800 % pixel cache returning a pointer to the cache.
4802 % The format of the ReferencePixelCache method is:
4804 % Cache ReferencePixelCache(Cache cache_info)
4806 % A description of each parameter follows:
4808 % o cache_info: the pixel cache.
4811 MagickExport Cache ReferencePixelCache(Cache cache)
4816 assert(cache != (Cache *) NULL);
4817 cache_info=(CacheInfo *) cache;
4818 assert(cache_info->signature == MagickSignature);
4819 LockSemaphoreInfo(cache_info->semaphore);
4820 cache_info->reference_count++;
4821 UnlockSemaphoreInfo(cache_info->semaphore);
4826 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4830 + S e t P i x e l C a c h e M e t h o d s %
4834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4836 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4838 % The format of the SetPixelCacheMethods() method is:
4840 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4842 % A description of each parameter follows:
4844 % o cache: the pixel cache.
4846 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4849 MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4854 GetOneAuthenticPixelFromHandler
4855 get_one_authentic_pixel_from_handler;
4857 GetOneVirtualPixelFromHandler
4858 get_one_virtual_pixel_from_handler;
4861 Set cache pixel methods.
4863 assert(cache != (Cache) NULL);
4864 assert(cache_methods != (CacheMethods *) NULL);
4865 cache_info=(CacheInfo *) cache;
4866 assert(cache_info->signature == MagickSignature);
4867 if (cache_info->debug != MagickFalse)
4868 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4869 cache_info->filename);
4870 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4871 cache_info->methods.get_virtual_pixel_handler=
4872 cache_methods->get_virtual_pixel_handler;
4873 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4874 cache_info->methods.destroy_pixel_handler=
4875 cache_methods->destroy_pixel_handler;
4876 if (cache_methods->get_virtual_indexes_from_handler !=
4877 (GetVirtualIndexesFromHandler) NULL)
4878 cache_info->methods.get_virtual_indexes_from_handler=
4879 cache_methods->get_virtual_indexes_from_handler;
4880 if (cache_methods->get_authentic_pixels_handler !=
4881 (GetAuthenticPixelsHandler) NULL)
4882 cache_info->methods.get_authentic_pixels_handler=
4883 cache_methods->get_authentic_pixels_handler;
4884 if (cache_methods->queue_authentic_pixels_handler !=
4885 (QueueAuthenticPixelsHandler) NULL)
4886 cache_info->methods.queue_authentic_pixels_handler=
4887 cache_methods->queue_authentic_pixels_handler;
4888 if (cache_methods->sync_authentic_pixels_handler !=
4889 (SyncAuthenticPixelsHandler) NULL)
4890 cache_info->methods.sync_authentic_pixels_handler=
4891 cache_methods->sync_authentic_pixels_handler;
4892 if (cache_methods->get_authentic_pixels_from_handler !=
4893 (GetAuthenticPixelsFromHandler) NULL)
4894 cache_info->methods.get_authentic_pixels_from_handler=
4895 cache_methods->get_authentic_pixels_from_handler;
4896 if (cache_methods->get_authentic_indexes_from_handler !=
4897 (GetAuthenticIndexesFromHandler) NULL)
4898 cache_info->methods.get_authentic_indexes_from_handler=
4899 cache_methods->get_authentic_indexes_from_handler;
4900 get_one_virtual_pixel_from_handler=
4901 cache_info->methods.get_one_virtual_pixel_from_handler;
4902 if (get_one_virtual_pixel_from_handler !=
4903 (GetOneVirtualPixelFromHandler) NULL)
4904 cache_info->methods.get_one_virtual_pixel_from_handler=
4905 cache_methods->get_one_virtual_pixel_from_handler;
4906 get_one_authentic_pixel_from_handler=
4907 cache_methods->get_one_authentic_pixel_from_handler;
4908 if (get_one_authentic_pixel_from_handler !=
4909 (GetOneAuthenticPixelFromHandler) NULL)
4910 cache_info->methods.get_one_authentic_pixel_from_handler=
4911 cache_methods->get_one_authentic_pixel_from_handler;
4915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4919 + S e t P i x e l C a c h e N e x u s P i x e l s %
4923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4925 % SetPixelCacheNexusPixels() defines the region of the cache for the
4926 % specified cache nexus.
4928 % The format of the SetPixelCacheNexusPixels() method is:
4930 % PixelPacket SetPixelCacheNexusPixels(const Image *image,
4931 % const RectangleInfo *region,NexusInfo *nexus_info,
4932 % ExceptionInfo *exception)
4934 % A description of each parameter follows:
4936 % o image: the image.
4938 % o region: A pointer to the RectangleInfo structure that defines the
4939 % region of this particular cache nexus.
4941 % o nexus_info: the cache nexus to set.
4943 % o exception: return any errors or warnings in this structure.
4947 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4948 NexusInfo *nexus_info,ExceptionInfo *exception)
4950 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4951 return(MagickFalse);
4952 nexus_info->mapped=MagickFalse;
4953 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4954 nexus_info->length);
4955 if (nexus_info->cache == (PixelPacket *) NULL)
4957 nexus_info->mapped=MagickTrue;
4958 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4959 nexus_info->length);
4961 if (nexus_info->cache == (PixelPacket *) NULL)
4963 (void) ThrowMagickException(exception,GetMagickModule(),
4964 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4965 cache_info->filename);
4966 return(MagickFalse);
4971 static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4972 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4984 cache_info=(CacheInfo *) image->cache;
4985 assert(cache_info->signature == MagickSignature);
4986 if (cache_info->type == UndefinedCache)
4987 return((PixelPacket *) NULL);
4988 nexus_info->region=(*region);
4989 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4990 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
4996 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4997 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4998 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4999 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
5000 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5001 ((nexus_info->region.width == cache_info->columns) ||
5002 ((nexus_info->region.width % cache_info->columns) == 0)))))
5008 Pixels are accessed directly from memory.
5010 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5011 nexus_info->region.x;
5012 nexus_info->pixels=cache_info->pixels+offset;
5013 nexus_info->indexes=(IndexPacket *) NULL;
5014 if (cache_info->active_index_channel != MagickFalse)
5015 nexus_info->indexes=cache_info->indexes+offset;
5016 return(nexus_info->pixels);
5020 Pixels are stored in a cache region until they are synced to the cache.
5022 number_pixels=(MagickSizeType) nexus_info->region.width*
5023 nexus_info->region.height;
5024 length=number_pixels*sizeof(PixelPacket);
5025 if (cache_info->active_index_channel != MagickFalse)
5026 length+=number_pixels*sizeof(IndexPacket);
5027 if (nexus_info->cache == (PixelPacket *) NULL)
5029 nexus_info->length=length;
5030 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5031 if (status == MagickFalse)
5033 nexus_info->length=0;
5034 return((PixelPacket *) NULL);
5038 if (nexus_info->length != length)
5040 RelinquishCacheNexusPixels(nexus_info);
5041 nexus_info->length=length;
5042 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5043 if (status == MagickFalse)
5045 nexus_info->length=0;
5046 return((PixelPacket *) NULL);
5049 nexus_info->pixels=nexus_info->cache;
5050 nexus_info->indexes=(IndexPacket *) NULL;
5051 if (cache_info->active_index_channel != MagickFalse)
5052 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5053 return(nexus_info->pixels);
5057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5061 % 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 %
5065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5067 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5068 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5069 % access that is outside the boundaries of the image cache.
5071 % The format of the SetPixelCacheVirtualMethod() method is:
5073 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5074 % const VirtualPixelMethod virtual_pixel_method)
5076 % A description of each parameter follows:
5078 % o image: the image.
5080 % o virtual_pixel_method: choose the type of virtual pixel.
5083 MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5084 const VirtualPixelMethod virtual_pixel_method)
5092 assert(image != (Image *) NULL);
5093 assert(image->signature == MagickSignature);
5094 if (image->debug != MagickFalse)
5095 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5096 assert(image->cache != (Cache) NULL);
5097 cache_info=(CacheInfo *) image->cache;
5098 assert(cache_info->signature == MagickSignature);
5099 method=cache_info->virtual_pixel_method;
5100 cache_info->virtual_pixel_method=virtual_pixel_method;
5105 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5109 + 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 %
5113 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5115 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5116 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5117 % is synced, otherwise MagickFalse.
5119 % The format of the SyncAuthenticPixelCacheNexus() method is:
5121 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5122 % NexusInfo *nexus_info,ExceptionInfo *exception)
5124 % A description of each parameter follows:
5126 % o image: the image.
5128 % o nexus_info: the cache nexus to sync.
5130 % o exception: return any errors or warnings in this structure.
5133 MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5134 NexusInfo *nexus_info,ExceptionInfo *exception)
5143 Transfer pixels to the cache.
5145 assert(image != (Image *) NULL);
5146 assert(image->signature == MagickSignature);
5147 if (image->cache == (Cache) NULL)
5148 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5149 cache_info=(CacheInfo *) image->cache;
5150 assert(cache_info->signature == MagickSignature);
5151 if (cache_info->type == UndefinedCache)
5152 return(MagickFalse);
5153 if ((image->clip_mask != (Image *) NULL) &&
5154 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5155 return(MagickFalse);
5156 if ((image->mask != (Image *) NULL) &&
5157 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5158 return(MagickFalse);
5159 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5161 assert(cache_info->signature == MagickSignature);
5162 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5163 if ((cache_info->active_index_channel != MagickFalse) &&
5164 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5165 return(MagickFalse);
5170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5174 + S y n c A u t h e n t i c P i x e l C a c h e %
5178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5180 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5181 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5182 % otherwise MagickFalse.
5184 % The format of the SyncAuthenticPixelsCache() method is:
5186 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5187 % ExceptionInfo *exception)
5189 % A description of each parameter follows:
5191 % o image: the image.
5193 % o exception: return any errors or warnings in this structure.
5196 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5197 ExceptionInfo *exception)
5203 id = GetOpenMPThreadId();
5205 assert(image != (Image *) NULL);
5206 assert(image->signature == MagickSignature);
5207 assert(image->cache != (Cache) NULL);
5208 cache_info=(CacheInfo *) image->cache;
5209 assert(cache_info->signature == MagickSignature);
5210 assert(id < (int) cache_info->number_threads);
5211 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5220 % S y n c A u t h e n t i c P i x e l s %
5224 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5226 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5227 % The method returns MagickTrue if the pixel region is flushed, otherwise
5230 % The format of the SyncAuthenticPixels() method is:
5232 % MagickBooleanType SyncAuthenticPixels(Image *image,
5233 % ExceptionInfo *exception)
5235 % A description of each parameter follows:
5237 % o image: the image.
5239 % o exception: return any errors or warnings in this structure.
5242 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5243 ExceptionInfo *exception)
5249 id = GetOpenMPThreadId();
5251 assert(image != (Image *) NULL);
5252 assert(image->signature == MagickSignature);
5253 assert(image->cache != (Cache) NULL);
5254 cache_info=(CacheInfo *) image->cache;
5255 assert(cache_info->signature == MagickSignature);
5256 if (cache_info->methods.sync_authentic_pixels_handler !=
5257 (SyncAuthenticPixelsHandler) NULL)
5258 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5259 assert(id < (int) cache_info->number_threads);
5260 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5269 + W r i t e P i x e l C a c h e I n d e x e s %
5273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5275 % WritePixelCacheIndexes() writes the colormap indexes to the specified
5276 % region of the pixel cache.
5278 % The format of the WritePixelCacheIndexes() method is:
5280 % MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5281 % NexusInfo *nexus_info,ExceptionInfo *exception)
5283 % A description of each parameter follows:
5285 % o cache_info: the pixel cache.
5287 % o nexus_info: the cache nexus to write the colormap indexes.
5289 % o exception: return any errors or warnings in this structure.
5292 static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5293 NexusInfo *nexus_info,ExceptionInfo *exception)
5303 register const IndexPacket
5312 if (cache_info->active_index_channel == MagickFalse)
5313 return(MagickFalse);
5314 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5316 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5317 nexus_info->region.x;
5318 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5319 rows=nexus_info->region.height;
5320 extent=(MagickSizeType) length*rows;
5321 p=nexus_info->indexes;
5322 switch (cache_info->type)
5327 register IndexPacket
5331 Write indexes to memory.
5333 if ((cache_info->columns == nexus_info->region.width) &&
5334 (extent == (MagickSizeType) ((size_t) extent)))
5339 q=cache_info->indexes+offset;
5340 for (y=0; y < (ssize_t) rows; y++)
5342 (void) memcpy(q,p,(size_t) length);
5343 p+=nexus_info->region.width;
5344 q+=cache_info->columns;
5351 Write indexes to disk.
5353 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5355 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5356 cache_info->cache_filename);
5357 return(MagickFalse);
5359 if ((cache_info->columns == nexus_info->region.width) &&
5360 (extent <= MagickMaxBufferExtent))
5365 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5366 for (y=0; y < (ssize_t) rows; y++)
5368 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5369 sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5371 if ((MagickSizeType) count < length)
5373 p+=nexus_info->region.width;
5374 offset+=cache_info->columns;
5376 if (y < (ssize_t) rows)
5378 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5379 cache_info->cache_filename);
5380 return(MagickFalse);
5387 if ((cache_info->debug != MagickFalse) &&
5388 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5389 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5390 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5391 nexus_info->region.width,(double) nexus_info->region.height,(double)
5392 nexus_info->region.x,(double) nexus_info->region.y);
5397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5401 + W r i t e C a c h e P i x e l s %
5405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5407 % WritePixelCachePixels() writes image pixels to the specified region of the
5410 % The format of the WritePixelCachePixels() method is:
5412 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5413 % NexusInfo *nexus_info,ExceptionInfo *exception)
5415 % A description of each parameter follows:
5417 % o cache_info: the pixel cache.
5419 % o nexus_info: the cache nexus to write the pixels.
5421 % o exception: return any errors or warnings in this structure.
5424 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5425 NexusInfo *nexus_info,ExceptionInfo *exception)
5435 register const PixelPacket
5444 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5446 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5447 nexus_info->region.x;
5448 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5449 rows=nexus_info->region.height;
5451 p=nexus_info->pixels;
5452 switch (cache_info->type)
5457 register PixelPacket
5461 Write pixels to memory.
5463 if ((cache_info->columns == nexus_info->region.width) &&
5464 (extent == (MagickSizeType) ((size_t) extent)))
5469 q=cache_info->pixels+offset;
5470 for (y=0; y < (ssize_t) rows; y++)
5472 (void) memcpy(q,p,(size_t) length);
5473 p+=nexus_info->region.width;
5474 q+=cache_info->columns;
5481 Write pixels to disk.
5483 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5485 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5486 cache_info->cache_filename);
5487 return(MagickFalse);
5489 if ((cache_info->columns == nexus_info->region.width) &&
5490 (extent <= MagickMaxBufferExtent))
5495 for (y=0; y < (ssize_t) rows; y++)
5497 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5498 sizeof(*p),length,(const unsigned char *) p);
5499 if ((MagickSizeType) count < length)
5501 p+=nexus_info->region.width;
5502 offset+=cache_info->columns;
5504 if (y < (ssize_t) rows)
5506 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5507 cache_info->cache_filename);
5508 return(MagickFalse);
5515 if ((cache_info->debug != MagickFalse) &&
5516 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5517 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5518 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5519 nexus_info->region.width,(double) nexus_info->region.height,(double)
5520 nexus_info->region.x,(double) nexus_info->region.y);