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-2011 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 (lseek(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 (lseek(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*
828 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
830 for (y=0; y < (ssize_t) rows; y++)
832 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
833 length,(unsigned char *) indexes);
834 if ((MagickSizeType) count != length)
836 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
837 (unsigned char *) indexes);
838 if ((MagickSizeType) count != length)
840 source_offset+=cache_info->columns*sizeof(*indexes);
841 offset+=clone_info->columns*sizeof(*indexes);
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*
856 for (y=0; y < (ssize_t) rows; y++)
858 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
859 length,(unsigned char *) indexes);
860 if ((MagickSizeType) count != length)
862 offset+=clone_info->columns*sizeof(*indexes);
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);
889 for (y=0; y < (ssize_t) rows; y++)
891 count=ReadPixelCacheRegion(cache_info,cache_info->offset+source_offset,
892 length,(unsigned char *) pixels);
893 if ((MagickSizeType) count != length)
895 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
896 (unsigned char *) pixels);
897 if ((MagickSizeType) count != length)
899 source_offset+=cache_info->columns*sizeof(*pixels);
900 offset+=clone_info->columns*sizeof(*pixels);
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 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
912 (void) ResetMagickMemory(pixels,0,(size_t) length);
913 offset=(MagickOffsetType) columns*sizeof(*pixels);
914 for (y=0; y < (ssize_t) rows; y++)
916 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
917 (unsigned char *) pixels);
918 if ((MagickSizeType) count != length)
920 offset+=clone_info->columns*sizeof(*pixels);
922 if (y < (ssize_t) rows)
924 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
925 ThrowFileException(exception,CacheError,"UnableToCloneCache",
926 cache_info->cache_filename);
930 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
934 static MagickBooleanType CloneDiskToMemoryPixelCache(CacheInfo *clone_info,
935 CacheInfo *cache_info,ExceptionInfo *exception)
955 if (cache_info->debug != MagickFalse)
956 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"disk => memory");
957 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
959 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
960 cache_info->cache_filename);
963 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
964 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
965 if ((clone_info->active_index_channel != MagickFalse) &&
966 (cache_info->active_index_channel != MagickFalse))
975 length=MagickMax(clone_info->columns,cache_info->columns)*
977 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
978 if (indexes == (IndexPacket *) NULL)
980 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
981 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
984 (void) ResetMagickMemory(indexes,0,(size_t) length);
985 length=columns*sizeof(IndexPacket);
986 offset=(MagickOffsetType) cache_info->columns*cache_info->rows*
988 q=clone_info->indexes;
989 for (y=0; y < (ssize_t) rows; y++)
991 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,
992 length,(unsigned char *) indexes);
993 if ((MagickSizeType) count != length)
995 (void) memcpy(q,indexes,(size_t) length);
996 if ((MagickSizeType) count != length)
998 offset+=cache_info->columns*sizeof(*indexes);
999 q+=clone_info->columns;
1001 if (y < (ssize_t) rows)
1003 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1004 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1005 cache_info->cache_filename);
1006 return(MagickFalse);
1008 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1013 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1014 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1015 if (pixels == (PixelPacket *) NULL)
1017 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1018 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1019 return(MagickFalse);
1021 (void) ResetMagickMemory(pixels,0,(size_t) length);
1022 length=columns*sizeof(*pixels);
1024 q=clone_info->pixels;
1025 for (y=0; y < (ssize_t) rows; y++)
1027 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset,length,
1028 (unsigned char *) pixels);
1029 if ((MagickSizeType) count != length)
1031 (void) memcpy(q,pixels,(size_t) length);
1032 offset+=cache_info->columns*sizeof(*pixels);
1033 q+=clone_info->columns;
1035 if (y < (ssize_t) rows)
1037 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1038 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1039 cache_info->cache_filename);
1040 return(MagickFalse);
1042 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1046 static MagickBooleanType CloneMemoryToDiskPixelCache(CacheInfo *clone_info,
1047 CacheInfo *cache_info,ExceptionInfo *exception)
1056 register PixelPacket
1067 if (cache_info->debug != MagickFalse)
1068 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => disk");
1069 if (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse)
1071 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
1072 clone_info->cache_filename);
1073 return(MagickFalse);
1075 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1076 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1077 if ((clone_info->active_index_channel != MagickFalse) &&
1078 (cache_info->active_index_channel != MagickFalse))
1080 register IndexPacket
1085 Clone cache indexes.
1087 length=MagickMax(clone_info->columns,cache_info->columns)*
1089 indexes=(IndexPacket *) AcquireMagickMemory((size_t) length);
1090 if (indexes == (IndexPacket *) NULL)
1092 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1093 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1094 return(MagickFalse);
1096 (void) ResetMagickMemory(indexes,0,(size_t) length);
1097 length=columns*sizeof(*indexes);
1098 p=cache_info->indexes;
1099 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1101 for (y=0; y < (ssize_t) rows; y++)
1103 (void) memcpy(indexes,p,(size_t) length);
1104 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1105 (unsigned char *) indexes);
1106 if ((MagickSizeType) count != length)
1108 p+=cache_info->columns;
1109 offset+=clone_info->columns*sizeof(*indexes);
1111 if (y < (ssize_t) rows)
1113 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1114 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1115 cache_info->cache_filename);
1116 return(MagickFalse);
1118 if (clone_info->columns > cache_info->columns)
1120 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1121 (void) ResetMagickMemory(indexes,0,(size_t) length);
1122 offset=(MagickOffsetType) clone_info->columns*clone_info->rows*
1124 for (y=0; y < (ssize_t) rows; y++)
1126 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,
1127 length,(unsigned char *) indexes);
1128 if ((MagickSizeType) count != length)
1130 offset+=clone_info->columns*sizeof(*indexes);
1132 if (y < (ssize_t) rows)
1134 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1135 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1136 cache_info->cache_filename);
1137 return(MagickFalse);
1140 indexes=(IndexPacket *) RelinquishMagickMemory(indexes);
1145 length=MagickMax(clone_info->columns,cache_info->columns)*sizeof(*pixels);
1146 pixels=(PixelPacket *) AcquireMagickMemory((size_t) length);
1147 if (pixels == (PixelPacket *) NULL)
1149 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
1150 "MemoryAllocationFailed","`%s'",cache_info->cache_filename);
1151 return(MagickFalse);
1153 (void) ResetMagickMemory(pixels,0,(size_t) length);
1154 length=columns*sizeof(*pixels);
1155 p=cache_info->pixels;
1157 for (y=0; y < (ssize_t) rows; y++)
1159 (void) memcpy(pixels,p,(size_t) length);
1160 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1161 (unsigned char *) pixels);
1162 if ((MagickSizeType) count != length)
1164 p+=cache_info->columns;
1165 offset+=clone_info->columns*sizeof(*pixels);
1167 if (y < (ssize_t) rows)
1169 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1170 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1171 cache_info->cache_filename);
1172 return(MagickFalse);
1174 if (clone_info->columns > cache_info->columns)
1176 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1177 (void) ResetMagickMemory(pixels,0,(size_t) length);
1178 offset=(MagickOffsetType) columns*sizeof(*pixels);
1179 for (y=0; y < (ssize_t) rows; y++)
1181 count=WritePixelCacheRegion(clone_info,clone_info->offset+offset,length,
1182 (unsigned char *) pixels);
1183 if ((MagickSizeType) count != length)
1185 offset+=clone_info->columns*sizeof(*pixels);
1187 if (y < (ssize_t) rows)
1189 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1190 ThrowFileException(exception,CacheError,"UnableToCloneCache",
1191 cache_info->cache_filename);
1192 return(MagickFalse);
1195 pixels=(PixelPacket *) RelinquishMagickMemory(pixels);
1199 static MagickBooleanType CloneMemoryToMemoryPixelCache(CacheInfo *clone_info,
1200 CacheInfo *cache_info,ExceptionInfo *magick_unused(exception))
1202 register PixelPacket
1204 *restrict source_pixels;
1214 if (cache_info->debug != MagickFalse)
1215 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"memory => memory");
1216 columns=(size_t) MagickMin(clone_info->columns,cache_info->columns);
1217 rows=(size_t) MagickMin(clone_info->rows,cache_info->rows);
1218 if ((clone_info->active_index_channel != MagickFalse) &&
1219 (cache_info->active_index_channel != MagickFalse))
1221 register IndexPacket
1226 Clone cache indexes.
1228 length=columns*sizeof(*indexes);
1229 if (clone_info->columns == cache_info->columns)
1230 (void) memcpy(clone_info->indexes,cache_info->indexes,length*rows);
1233 source_indexes=cache_info->indexes;
1234 indexes=clone_info->indexes;
1235 for (y=0; y < (ssize_t) rows; y++)
1237 (void) memcpy(indexes,source_indexes,length);
1238 source_indexes+=cache_info->columns;
1239 indexes+=clone_info->columns;
1241 if (clone_info->columns > cache_info->columns)
1243 length=(clone_info->columns-cache_info->columns)*sizeof(*indexes);
1244 indexes=clone_info->indexes+cache_info->columns;
1245 for (y=0; y < (ssize_t) rows; y++)
1247 (void) ResetMagickMemory(indexes,0,length);
1248 indexes+=clone_info->columns;
1256 length=columns*sizeof(*pixels);
1257 if (clone_info->columns == cache_info->columns)
1258 (void) memcpy(clone_info->pixels,cache_info->pixels,length*rows);
1261 source_pixels=cache_info->pixels;
1262 pixels=clone_info->pixels;
1263 for (y=0; y < (ssize_t) rows; y++)
1265 (void) memcpy(pixels,source_pixels,length);
1266 source_pixels+=cache_info->columns;
1267 pixels+=clone_info->columns;
1269 if (clone_info->columns > cache_info->columns)
1271 length=(clone_info->columns-cache_info->columns)*sizeof(*pixels);
1272 pixels=clone_info->pixels+cache_info->columns;
1273 for (y=0; y < (ssize_t) rows; y++)
1275 (void) ResetMagickMemory(pixels,0,length);
1276 pixels+=clone_info->columns;
1283 static MagickBooleanType ClonePixelCachePixels(CacheInfo *clone_info,
1284 CacheInfo *cache_info,ExceptionInfo *exception)
1286 if (cache_info->type == PingCache)
1288 if ((clone_info->type != DiskCache) && (cache_info->type != DiskCache))
1289 return(CloneMemoryToMemoryPixelCache(clone_info,cache_info,exception));
1290 if ((clone_info->type == DiskCache) && (cache_info->type == DiskCache))
1291 return(CloneDiskToDiskPixelCache(clone_info,cache_info,exception));
1292 if (cache_info->type == DiskCache)
1293 return(CloneDiskToMemoryPixelCache(clone_info,cache_info,exception));
1294 return(CloneMemoryToDiskPixelCache(clone_info,cache_info,exception));
1298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302 + C l o n e P i x e l C a c h e M e t h o d s %
1306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308 % ClonePixelCacheMethods() clones the pixel cache methods from one cache to
1311 % The format of the ClonePixelCacheMethods() method is:
1313 % void ClonePixelCacheMethods(Cache clone,const Cache cache)
1315 % A description of each parameter follows:
1317 % o clone: Specifies a pointer to a Cache structure.
1319 % o cache: the pixel cache.
1322 MagickExport void ClonePixelCacheMethods(Cache clone,const Cache cache)
1328 assert(clone != (Cache) NULL);
1329 source_info=(CacheInfo *) clone;
1330 assert(source_info->signature == MagickSignature);
1331 if (source_info->debug != MagickFalse)
1332 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1333 source_info->filename);
1334 assert(cache != (Cache) NULL);
1335 cache_info=(CacheInfo *) cache;
1336 assert(cache_info->signature == MagickSignature);
1337 source_info->methods=cache_info->methods;
1341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1345 + D e s t r o y I m a g e P i x e l C a c h e %
1349 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1351 % DestroyImagePixelCache() deallocates memory associated with the pixel cache.
1353 % The format of the DestroyImagePixelCache() method is:
1355 % void DestroyImagePixelCache(Image *image)
1357 % A description of each parameter follows:
1359 % o image: the image.
1362 static void DestroyImagePixelCache(Image *image)
1364 assert(image != (Image *) NULL);
1365 assert(image->signature == MagickSignature);
1366 if (image->debug != MagickFalse)
1367 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1368 if (image->cache == (void *) NULL)
1370 image->cache=DestroyPixelCache(image->cache);
1374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1378 + D e s t r o y I m a g e P i x e l s %
1382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1384 % DestroyImagePixels() deallocates memory associated with the pixel cache.
1386 % The format of the DestroyImagePixels() method is:
1388 % void DestroyImagePixels(Image *image)
1390 % A description of each parameter follows:
1392 % o image: the image.
1395 MagickExport void DestroyImagePixels(Image *image)
1400 assert(image != (const Image *) NULL);
1401 assert(image->signature == MagickSignature);
1402 if (image->debug != MagickFalse)
1403 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1404 assert(image->cache != (Cache) NULL);
1405 cache_info=(CacheInfo *) image->cache;
1406 assert(cache_info->signature == MagickSignature);
1407 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1409 cache_info->methods.destroy_pixel_handler(image);
1412 image->cache=DestroyPixelCache(image->cache);
1416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420 + D e s t r o y P i x e l C a c h e %
1424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426 % DestroyPixelCache() deallocates memory associated with the pixel cache.
1428 % The format of the DestroyPixelCache() method is:
1430 % Cache DestroyPixelCache(Cache cache)
1432 % A description of each parameter follows:
1434 % o cache: the pixel cache.
1438 static inline void RelinquishPixelCachePixels(CacheInfo *cache_info)
1440 switch (cache_info->type)
1444 if (cache_info->mapped == MagickFalse)
1445 cache_info->pixels=(PixelPacket *) RelinquishMagickMemory(
1446 cache_info->pixels);
1448 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,
1449 (size_t) cache_info->length);
1450 RelinquishMagickResource(MemoryResource,cache_info->length);
1455 cache_info->pixels=(PixelPacket *) UnmapBlob(cache_info->pixels,(size_t)
1456 cache_info->length);
1457 RelinquishMagickResource(MapResource,cache_info->length);
1461 if (cache_info->file != -1)
1462 (void) ClosePixelCacheOnDisk(cache_info);
1463 RelinquishMagickResource(DiskResource,cache_info->length);
1469 cache_info->type=UndefinedCache;
1470 cache_info->mapped=MagickFalse;
1471 cache_info->indexes=(IndexPacket *) NULL;
1474 MagickExport Cache DestroyPixelCache(Cache cache)
1479 assert(cache != (Cache) NULL);
1480 cache_info=(CacheInfo *) cache;
1481 assert(cache_info->signature == MagickSignature);
1482 if (cache_info->debug != MagickFalse)
1483 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1484 cache_info->filename);
1485 LockSemaphoreInfo(cache_info->semaphore);
1486 cache_info->reference_count--;
1487 if (cache_info->reference_count != 0)
1489 UnlockSemaphoreInfo(cache_info->semaphore);
1490 return((Cache) NULL);
1492 UnlockSemaphoreInfo(cache_info->semaphore);
1493 if (cache_resources != (SplayTreeInfo *) NULL)
1494 (void) DeleteNodeByValueFromSplayTree(cache_resources,cache_info);
1495 if (cache_info->debug != MagickFalse)
1498 message[MaxTextExtent];
1500 (void) FormatMagickString(message,MaxTextExtent,"destroy %s",
1501 cache_info->filename);
1502 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",message);
1504 if ((cache_info->mode == ReadMode) || ((cache_info->type != MapCache) &&
1505 (cache_info->type != DiskCache)))
1506 RelinquishPixelCachePixels(cache_info);
1509 RelinquishPixelCachePixels(cache_info);
1510 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1512 *cache_info->cache_filename='\0';
1513 if (cache_info->nexus_info != (NexusInfo **) NULL)
1514 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1515 cache_info->number_threads);
1516 if (cache_info->random_info != (RandomInfo *) NULL)
1517 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1518 if (cache_info->disk_semaphore != (SemaphoreInfo *) NULL)
1519 DestroySemaphoreInfo(&cache_info->disk_semaphore);
1520 if (cache_info->semaphore != (SemaphoreInfo *) NULL)
1521 DestroySemaphoreInfo(&cache_info->semaphore);
1522 cache_info->signature=(~MagickSignature);
1523 cache_info=(CacheInfo *) RelinquishMagickMemory(cache_info);
1529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533 + D e s t r o y P i x e l C a c h e N e x u s %
1537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1539 % DestroyPixelCacheNexus() destroys a pixel cache nexus.
1541 % The format of the DestroyPixelCacheNexus() method is:
1543 % NexusInfo **DestroyPixelCacheNexus(NexusInfo *nexus_info,
1544 % const size_t number_threads)
1546 % A description of each parameter follows:
1548 % o nexus_info: the nexus to destroy.
1550 % o number_threads: the number of nexus threads.
1554 static inline void RelinquishCacheNexusPixels(NexusInfo *nexus_info)
1556 if (nexus_info->mapped == MagickFalse)
1557 (void) RelinquishMagickMemory(nexus_info->cache);
1559 (void) UnmapBlob(nexus_info->cache,(size_t) nexus_info->length);
1560 nexus_info->cache=(PixelPacket *) NULL;
1561 nexus_info->pixels=(PixelPacket *) NULL;
1562 nexus_info->indexes=(IndexPacket *) NULL;
1563 nexus_info->length=0;
1564 nexus_info->mapped=MagickFalse;
1567 MagickExport NexusInfo **DestroyPixelCacheNexus(NexusInfo **nexus_info,
1568 const size_t number_threads)
1573 assert(nexus_info != (NexusInfo **) NULL);
1574 for (i=0; i < (ssize_t) number_threads; i++)
1576 if (nexus_info[i]->cache != (PixelPacket *) NULL)
1577 RelinquishCacheNexusPixels(nexus_info[i]);
1578 nexus_info[i]->signature=(~MagickSignature);
1579 nexus_info[i]=(NexusInfo *) RelinquishAlignedMemory(nexus_info[i]);
1581 nexus_info=(NexusInfo **) RelinquishMagickMemory(nexus_info);
1586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590 + 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 %
1594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596 % GetAuthenticIndexesFromCache() returns the indexes associated with the last
1597 % call to QueueAuthenticPixelsCache() or GetAuthenticPixelsCache().
1599 % The format of the GetAuthenticIndexesFromCache() method is:
1601 % IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1603 % A description of each parameter follows:
1605 % o image: the image.
1608 static IndexPacket *GetAuthenticIndexesFromCache(const Image *image)
1614 id = GetOpenMPThreadId();
1616 assert(image != (const Image *) NULL);
1617 assert(image->signature == MagickSignature);
1618 assert(image->cache != (Cache) NULL);
1619 cache_info=(CacheInfo *) image->cache;
1620 assert(cache_info->signature == MagickSignature);
1621 assert(id < (int) cache_info->number_threads);
1622 return(GetPixelCacheNexusIndexes(image->cache,cache_info->nexus_info[id]));
1626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1630 % G e t A u t h e n t i c I n d e x Q u e u e %
1634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1636 % GetAuthenticIndexQueue() returns the authentic black channel or the colormap
1637 % indexes associated with the last call to QueueAuthenticPixels() or
1638 % GetVirtualPixels(). NULL is returned if the black channel or colormap
1639 % indexes are not available.
1641 % The format of the GetAuthenticIndexQueue() method is:
1643 % IndexPacket *GetAuthenticIndexQueue(const Image *image)
1645 % A description of each parameter follows:
1647 % o image: the image.
1650 MagickExport IndexPacket *GetAuthenticIndexQueue(const Image *image)
1656 id = GetOpenMPThreadId();
1658 assert(image != (const Image *) NULL);
1659 assert(image->signature == MagickSignature);
1660 assert(image->cache != (Cache) NULL);
1661 cache_info=(CacheInfo *) image->cache;
1662 assert(cache_info->signature == MagickSignature);
1663 if (cache_info->methods.get_authentic_indexes_from_handler !=
1664 (GetAuthenticIndexesFromHandler) NULL)
1665 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1666 assert(id < (int) cache_info->number_threads);
1667 return(GetPixelCacheNexusIndexes(cache_info,cache_info->nexus_info[id]));
1671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675 + 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 %
1679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1681 % GetAuthenticPixelCacheNexus() gets authentic pixels from the in-memory or
1682 % disk pixel cache as defined by the geometry parameters. A pointer to the
1683 % pixels is returned if the pixels are transferred, otherwise a NULL is
1686 % The format of the GetAuthenticPixelCacheNexus() method is:
1688 % PixelPacket *GetAuthenticPixelCacheNexus(Image *image,const ssize_t x,
1689 % const ssize_t y,const size_t columns,const size_t rows,
1690 % NexusInfo *nexus_info,ExceptionInfo *exception)
1692 % A description of each parameter follows:
1694 % o image: the image.
1696 % o x,y,columns,rows: These values define the perimeter of a region of
1699 % o nexus_info: the cache nexus to return.
1701 % o exception: return any errors or warnings in this structure.
1705 static inline MagickBooleanType IsNexusInCore(const CacheInfo *cache_info,
1706 NexusInfo *nexus_info)
1711 if (cache_info->type == PingCache)
1713 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
1714 nexus_info->region.x;
1715 return(nexus_info->pixels == (cache_info->pixels+offset) ? MagickTrue :
1719 MagickExport PixelPacket *GetAuthenticPixelCacheNexus(Image *image,
1720 const ssize_t x,const ssize_t y,const size_t columns,const size_t rows,
1721 NexusInfo *nexus_info,ExceptionInfo *exception)
1730 Transfer pixels from the cache.
1732 assert(image != (Image *) NULL);
1733 assert(image->signature == MagickSignature);
1734 pixels=QueueAuthenticNexus(image,x,y,columns,rows,nexus_info,exception);
1735 if (pixels == (PixelPacket *) NULL)
1736 return((PixelPacket *) NULL);
1737 cache_info=(CacheInfo *) image->cache;
1738 assert(cache_info->signature == MagickSignature);
1739 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
1741 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1742 return((PixelPacket *) NULL);
1743 if (cache_info->active_index_channel != MagickFalse)
1744 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1745 return((PixelPacket *) NULL);
1750 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1754 + 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 %
1758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1760 % GetAuthenticPixelsFromCache() returns the pixels associated with the last
1761 % call to the QueueAuthenticPixelsCache() or GetAuthenticPixelsCache() methods.
1763 % The format of the GetAuthenticPixelsFromCache() method is:
1765 % PixelPacket *GetAuthenticPixelsFromCache(const Image image)
1767 % A description of each parameter follows:
1769 % o image: the image.
1772 static PixelPacket *GetAuthenticPixelsFromCache(const Image *image)
1778 id = GetOpenMPThreadId();
1780 assert(image != (const Image *) NULL);
1781 assert(image->signature == MagickSignature);
1782 assert(image->cache != (Cache) NULL);
1783 cache_info=(CacheInfo *) image->cache;
1784 assert(cache_info->signature == MagickSignature);
1785 assert(id < (int) cache_info->number_threads);
1786 return(GetPixelCacheNexusPixels(image->cache,cache_info->nexus_info[id]));
1790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1794 % G e t A u t h e n t i c P i x e l Q u e u e %
1798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1800 % GetAuthenticPixelQueue() returns the authentic pixels associated with the
1801 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
1803 % The format of the GetAuthenticPixelQueue() method is:
1805 % PixelPacket *GetAuthenticPixelQueue(const Image image)
1807 % A description of each parameter follows:
1809 % o image: the image.
1812 MagickExport PixelPacket *GetAuthenticPixelQueue(const Image *image)
1818 id = GetOpenMPThreadId();
1820 assert(image != (const Image *) NULL);
1821 assert(image->signature == MagickSignature);
1822 assert(image->cache != (Cache) NULL);
1823 cache_info=(CacheInfo *) image->cache;
1824 assert(cache_info->signature == MagickSignature);
1825 if (cache_info->methods.get_authentic_pixels_from_handler !=
1826 (GetAuthenticPixelsFromHandler) NULL)
1827 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1828 assert(id < (int) cache_info->number_threads);
1829 return(GetPixelCacheNexusPixels(cache_info,cache_info->nexus_info[id]));
1833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1837 % G e t A u t h e n t i c P i x e l s %
1841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1843 % GetAuthenticPixels() obtains a pixel region for read/write access. If the
1844 % region is successfully accessed, a pointer to a PixelPacket array
1845 % representing the region is returned, otherwise NULL is returned.
1847 % The returned pointer may point to a temporary working copy of the pixels
1848 % or it may point to the original pixels in memory. Performance is maximized
1849 % if the selected region is part of one row, or one or more full rows, since
1850 % then there is opportunity to access the pixels in-place (without a copy)
1851 % if the image is in memory, or in a memory-mapped file. The returned pointer
1852 % must *never* be deallocated by the user.
1854 % Pixels accessed via the returned pointer represent a simple array of type
1855 % PixelPacket. If the image type is CMYK or if the storage class is
1856 % PseduoClass, call GetAuthenticIndexQueue() after invoking
1857 % GetAuthenticPixels() to obtain the black color component or colormap indexes
1858 % (of type IndexPacket) corresponding to the region. Once the PixelPacket
1859 % (and/or IndexPacket) array has been updated, the changes must be saved back
1860 % to the underlying image using SyncAuthenticPixels() or they may be lost.
1862 % The format of the GetAuthenticPixels() method is:
1864 % PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1865 % const ssize_t y,const size_t columns,const size_t rows,
1866 % ExceptionInfo *exception)
1868 % A description of each parameter follows:
1870 % o image: the image.
1872 % o x,y,columns,rows: These values define the perimeter of a region of
1875 % o exception: return any errors or warnings in this structure.
1878 MagickExport PixelPacket *GetAuthenticPixels(Image *image,const ssize_t x,
1879 const ssize_t y,const size_t columns,const size_t rows,
1880 ExceptionInfo *exception)
1886 id = GetOpenMPThreadId();
1888 assert(image != (Image *) NULL);
1889 assert(image->signature == MagickSignature);
1890 assert(image->cache != (Cache) NULL);
1891 cache_info=(CacheInfo *) image->cache;
1892 assert(cache_info->signature == MagickSignature);
1893 if (cache_info->methods.get_authentic_pixels_handler !=
1894 (GetAuthenticPixelsHandler) NULL)
1895 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1897 assert(id < (int) cache_info->number_threads);
1898 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1899 cache_info->nexus_info[id],exception));
1903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1907 + G e t A u t h e n t i c P i x e l s C a c h e %
1911 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1913 % GetAuthenticPixelsCache() gets pixels from the in-memory or disk pixel cache
1914 % as defined by the geometry parameters. A pointer to the pixels is returned
1915 % if the pixels are transferred, otherwise a NULL is returned.
1917 % The format of the GetAuthenticPixelsCache() method is:
1919 % PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1920 % const ssize_t y,const size_t columns,const size_t rows,
1921 % ExceptionInfo *exception)
1923 % A description of each parameter follows:
1925 % o image: the image.
1927 % o x,y,columns,rows: These values define the perimeter of a region of
1930 % o exception: return any errors or warnings in this structure.
1933 static PixelPacket *GetAuthenticPixelsCache(Image *image,const ssize_t x,
1934 const ssize_t y,const size_t columns,const size_t rows,
1935 ExceptionInfo *exception)
1941 id = GetOpenMPThreadId();
1943 assert(image != (const Image *) NULL);
1944 assert(image->signature == MagickSignature);
1945 assert(image->cache != (Cache) NULL);
1946 cache_info=(CacheInfo *) image->cache;
1947 if (cache_info == (Cache) NULL)
1948 return((PixelPacket *) NULL);
1949 assert(cache_info->signature == MagickSignature);
1950 assert(id < (int) cache_info->number_threads);
1951 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1952 cache_info->nexus_info[id],exception));
1956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1960 + G e t I m a g e E x t e n t %
1964 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1966 % GetImageExtent() returns the extent of the pixels associated with the
1967 % last call to QueueAuthenticPixels() or GetAuthenticPixels().
1969 % The format of the GetImageExtent() method is:
1971 % MagickSizeType GetImageExtent(const Image *image)
1973 % A description of each parameter follows:
1975 % o image: the image.
1978 MagickExport MagickSizeType GetImageExtent(const Image *image)
1984 id = GetOpenMPThreadId();
1986 assert(image != (Image *) NULL);
1987 assert(image->signature == MagickSignature);
1988 if (image->debug != MagickFalse)
1989 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1990 assert(image->cache != (Cache) NULL);
1991 cache_info=(CacheInfo *) image->cache;
1992 assert(cache_info->signature == MagickSignature);
1993 assert(id < (int) cache_info->number_threads);
1994 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[id]));
1998 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2002 + G e t I m a g e P i x e l C a c h e %
2006 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2008 % GetImagePixelCache() ensures that there is only a single reference to the
2009 % pixel cache to be modified, updating the provided cache pointer to point to
2010 % a clone of the original pixel cache if necessary.
2012 % The format of the GetImagePixelCache method is:
2014 % Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2015 % ExceptionInfo *exception)
2017 % A description of each parameter follows:
2019 % o image: the image.
2021 % o clone: any value other than MagickFalse clones the cache pixels.
2023 % o exception: return any errors or warnings in this structure.
2026 static inline MagickBooleanType ValidatePixelCacheMorphology(const Image *image)
2032 Does the image match the pixel cache morphology?
2034 cache_info=(CacheInfo *) image->cache;
2035 if ((image->storage_class != cache_info->storage_class) ||
2036 (image->colorspace != cache_info->colorspace) ||
2037 (image->columns != cache_info->columns) ||
2038 (image->rows != cache_info->rows) ||
2039 (cache_info->nexus_info == (NexusInfo **) NULL) ||
2040 (cache_info->number_threads < GetOpenMPMaximumThreads()))
2041 return(MagickFalse);
2045 static Cache GetImagePixelCache(Image *image,const MagickBooleanType clone,
2046 ExceptionInfo *exception)
2055 static MagickSizeType
2064 LockSemaphoreInfo(image->semaphore);
2065 if (cpu_throttle == 0)
2071 Set CPU throttle in milleseconds.
2073 cpu_throttle=MagickResourceInfinity;
2074 limit=GetEnvironmentValue("MAGICK_THROTTLE");
2075 if (limit == (char *) NULL)
2076 limit=GetPolicyValue("throttle");
2077 if (limit != (char *) NULL)
2079 cpu_throttle=(MagickSizeType) StringToInteger(limit);
2080 limit=DestroyString(limit);
2083 if ((cpu_throttle != MagickResourceInfinity) && ((cycles++ % 32) == 0))
2084 MagickDelay(cpu_throttle);
2085 if (time_limit == 0)
2088 Set the exire time in seconds.
2090 time_limit=GetMagickResourceLimit(TimeResource);
2091 cache_genesis=time((time_t *) NULL);
2093 if ((time_limit != MagickResourceInfinity) &&
2094 ((MagickSizeType) (time((time_t *) NULL)-cache_genesis) >= time_limit))
2095 ThrowFatalException(ResourceLimitFatalError,"TimeLimitExceeded");
2096 assert(image->cache != (Cache) NULL);
2097 cache_info=(CacheInfo *) image->cache;
2098 destroy=MagickFalse;
2099 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2101 LockSemaphoreInfo(cache_info->semaphore);
2102 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
2113 clone_image=(*image);
2114 clone_image.semaphore=AllocateSemaphoreInfo();
2115 clone_image.reference_count=1;
2116 clone_image.cache=ClonePixelCache(cache_info);
2117 clone_info=(CacheInfo *) clone_image.cache;
2118 status=OpenPixelCache(&clone_image,IOMode,exception);
2119 if (status != MagickFalse)
2121 if (clone != MagickFalse)
2122 status=ClonePixelCachePixels(clone_info,cache_info,exception);
2123 if (status != MagickFalse)
2126 image->cache=clone_image.cache;
2129 DestroySemaphoreInfo(&clone_image.semaphore);
2131 UnlockSemaphoreInfo(cache_info->semaphore);
2133 if (destroy != MagickFalse)
2134 cache_info=(CacheInfo *) DestroyPixelCache(cache_info);
2135 if (status != MagickFalse)
2138 Ensure the image matches the pixel cache morphology.
2140 image->taint=MagickTrue;
2141 image->type=UndefinedType;
2142 if (image->colorspace == GRAYColorspace)
2143 image->colorspace=RGBColorspace;
2144 if (ValidatePixelCacheMorphology(image) == MagickFalse)
2145 status=OpenPixelCache(image,IOMode,exception);
2147 UnlockSemaphoreInfo(image->semaphore);
2148 if (status == MagickFalse)
2149 return((Cache) NULL);
2150 return(image->cache);
2154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2158 % G e t O n e A u t h e n t i c P i x e l %
2162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2164 % GetOneAuthenticPixel() returns a single pixel at the specified (x,y)
2165 % location. The image background color is returned if an error occurs.
2167 % The format of the GetOneAuthenticPixel() method is:
2169 % MagickBooleanType GetOneAuthenticPixel(const Image image,const ssize_t x,
2170 % const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2172 % A description of each parameter follows:
2174 % o image: the image.
2176 % o x,y: These values define the location of the pixel to return.
2178 % o pixel: return a pixel at the specified (x,y) location.
2180 % o exception: return any errors or warnings in this structure.
2183 MagickExport MagickBooleanType GetOneAuthenticPixel(Image *image,
2184 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2192 assert(image != (Image *) NULL);
2193 assert(image->signature == MagickSignature);
2194 assert(image->cache != (Cache) NULL);
2195 cache_info=(CacheInfo *) image->cache;
2196 assert(cache_info->signature == MagickSignature);
2197 *pixel=image->background_color;
2198 if (cache_info->methods.get_one_authentic_pixel_from_handler !=
2199 (GetOneAuthenticPixelFromHandler) NULL)
2200 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,
2202 *pixel=image->background_color;
2203 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2204 if (pixels == (PixelPacket *) NULL)
2205 return(MagickFalse);
2211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2215 + 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 %
2219 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2221 % GetOneAuthenticPixelFromCache() returns a single pixel at the specified (x,y)
2222 % location. The image background color is returned if an error occurs.
2224 % The format of the GetOneAuthenticPixelFromCache() method is:
2226 % MagickBooleanType GetOneAuthenticPixelFromCache(const Image image,
2227 % const ssize_t x,const ssize_t y,PixelPacket *pixel,
2228 % ExceptionInfo *exception)
2230 % A description of each parameter follows:
2232 % o image: the image.
2234 % o x,y: These values define the location of the pixel to return.
2236 % o pixel: return a pixel at the specified (x,y) location.
2238 % o exception: return any errors or warnings in this structure.
2241 static MagickBooleanType GetOneAuthenticPixelFromCache(Image *image,
2242 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2248 id = GetOpenMPThreadId();
2253 assert(image != (const Image *) NULL);
2254 assert(image->signature == MagickSignature);
2255 assert(image->cache != (Cache) NULL);
2256 cache_info=(CacheInfo *) image->cache;
2257 assert(cache_info->signature == MagickSignature);
2258 *pixel=image->background_color;
2259 assert(id < (int) cache_info->number_threads);
2260 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2261 cache_info->nexus_info[id],exception);
2262 if (pixels == (PixelPacket *) NULL)
2263 return(MagickFalse);
2269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2273 % G e t O n e V i r t u a l M a g i c k P i x e l %
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2279 % GetOneVirtualMagickPixel() returns a single pixel at the specified (x,y)
2280 % location. The image background color is returned if an error occurs. If
2281 % you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2283 % The format of the GetOneVirtualMagickPixel() method is:
2285 % MagickBooleanType GetOneVirtualMagickPixel(const Image image,
2286 % const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2287 % ExceptionInfo exception)
2289 % A description of each parameter follows:
2291 % o image: the image.
2293 % o x,y: these values define the location of the pixel to return.
2295 % o pixel: return a pixel at the specified (x,y) location.
2297 % o exception: return any errors or warnings in this structure.
2300 MagickExport MagickBooleanType GetOneVirtualMagickPixel(const Image *image,
2301 const ssize_t x,const ssize_t y,MagickPixelPacket *pixel,
2302 ExceptionInfo *exception)
2308 id = GetOpenMPThreadId();
2310 register const IndexPacket
2313 register const PixelPacket
2316 assert(image != (const Image *) NULL);
2317 assert(image->signature == MagickSignature);
2318 assert(image->cache != (Cache) NULL);
2319 cache_info=(CacheInfo *) image->cache;
2320 assert(cache_info->signature == MagickSignature);
2321 assert(id < (int) cache_info->number_threads);
2322 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2323 1UL,1UL,cache_info->nexus_info[id],exception);
2324 GetMagickPixelPacket(image,pixel);
2325 if (pixels == (const PixelPacket *) NULL)
2326 return(MagickFalse);
2327 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[id]);
2328 SetMagickPixelPacket(image,pixels,indexes,pixel);
2333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337 % G e t O n e V i r t u a l M e t h o d P i x e l %
2341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2343 % GetOneVirtualMethodPixel() returns a single pixel at the specified (x,y)
2344 % location as defined by specified pixel method. The image background color
2345 % is returned if an error occurs. If you plan to modify the pixel, use
2346 % GetOneAuthenticPixel() instead.
2348 % The format of the GetOneVirtualMethodPixel() method is:
2350 % MagickBooleanType GetOneVirtualMethodPixel(const Image image,
2351 % const VirtualPixelMethod virtual_pixel_method,const ssize_t x,
2352 % const ssize_t y,Pixelpacket *pixel,ExceptionInfo exception)
2354 % A description of each parameter follows:
2356 % o image: the image.
2358 % o virtual_pixel_method: the virtual pixel method.
2360 % o x,y: These values define the location of the pixel to return.
2362 % o pixel: return a pixel at the specified (x,y) location.
2364 % o exception: return any errors or warnings in this structure.
2367 MagickExport MagickBooleanType GetOneVirtualMethodPixel(const Image *image,
2368 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2369 PixelPacket *pixel,ExceptionInfo *exception)
2375 id = GetOpenMPThreadId();
2380 assert(image != (const Image *) NULL);
2381 assert(image->signature == MagickSignature);
2382 assert(image->cache != (Cache) NULL);
2383 cache_info=(CacheInfo *) image->cache;
2384 assert(cache_info->signature == MagickSignature);
2385 *pixel=image->background_color;
2386 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2387 (GetOneVirtualPixelFromHandler) NULL)
2388 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2389 virtual_pixel_method,x,y,pixel,exception));
2390 assert(id < (int) cache_info->number_threads);
2391 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2392 cache_info->nexus_info[id],exception);
2393 if (pixels == (const PixelPacket *) NULL)
2394 return(MagickFalse);
2400 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2404 % G e t O n e V i r t u a l P i x e l %
2408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2410 % GetOneVirtualPixel() returns a single virtual pixel at the specified
2411 % (x,y) location. The image background color is returned if an error occurs.
2412 % If you plan to modify the pixel, use GetOneAuthenticPixel() instead.
2414 % The format of the GetOneVirtualPixel() method is:
2416 % MagickBooleanType GetOneVirtualPixel(const Image image,const ssize_t x,
2417 % const ssize_t y,PixelPacket *pixel,ExceptionInfo exception)
2419 % A description of each parameter follows:
2421 % o image: the image.
2423 % o x,y: These values define the location of the pixel to return.
2425 % o pixel: return a pixel at the specified (x,y) location.
2427 % o exception: return any errors or warnings in this structure.
2430 MagickExport MagickBooleanType GetOneVirtualPixel(const Image *image,
2431 const ssize_t x,const ssize_t y,PixelPacket *pixel,ExceptionInfo *exception)
2437 id = GetOpenMPThreadId();
2442 assert(image != (const Image *) NULL);
2443 assert(image->signature == MagickSignature);
2444 assert(image->cache != (Cache) NULL);
2445 cache_info=(CacheInfo *) image->cache;
2446 assert(cache_info->signature == MagickSignature);
2447 *pixel=image->background_color;
2448 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2449 (GetOneVirtualPixelFromHandler) NULL)
2450 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2451 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2452 assert(id < (int) cache_info->number_threads);
2453 pixels=GetVirtualPixelsFromNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2454 1UL,1UL,cache_info->nexus_info[id],exception);
2455 if (pixels == (const PixelPacket *) NULL)
2456 return(MagickFalse);
2462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2466 + 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 %
2470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2472 % GetOneVirtualPixelFromCache() returns a single virtual pixel at the
2473 % specified (x,y) location. The image background color is returned if an
2476 % The format of the GetOneVirtualPixelFromCache() method is:
2478 % MagickBooleanType GetOneVirtualPixelFromCache(const Image image,
2479 % const VirtualPixelPacket method,const ssize_t x,const ssize_t y,
2480 % PixelPacket *pixel,ExceptionInfo *exception)
2482 % A description of each parameter follows:
2484 % o image: the image.
2486 % o virtual_pixel_method: the virtual pixel method.
2488 % o x,y: These values define the location of the pixel to return.
2490 % o pixel: return a pixel at the specified (x,y) location.
2492 % o exception: return any errors or warnings in this structure.
2495 static MagickBooleanType GetOneVirtualPixelFromCache(const Image *image,
2496 const VirtualPixelMethod virtual_pixel_method,const ssize_t x,const ssize_t y,
2497 PixelPacket *pixel,ExceptionInfo *exception)
2503 id = GetOpenMPThreadId();
2508 assert(image != (const Image *) NULL);
2509 assert(image->signature == MagickSignature);
2510 assert(image->cache != (Cache) NULL);
2511 cache_info=(CacheInfo *) image->cache;
2512 assert(cache_info->signature == MagickSignature);
2513 assert(id < (int) cache_info->number_threads);
2514 *pixel=image->background_color;
2515 pixels=GetVirtualPixelsFromNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2516 cache_info->nexus_info[id],exception);
2517 if (pixels == (const PixelPacket *) NULL)
2518 return(MagickFalse);
2524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2528 + G e t P i x e l C a c h e C o l o r s p a c e %
2532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2534 % GetPixelCacheColorspace() returns the class type of the pixel cache.
2536 % The format of the GetPixelCacheColorspace() method is:
2538 % Colorspace GetPixelCacheColorspace(Cache cache)
2540 % A description of each parameter follows:
2542 % o cache: the pixel cache.
2545 MagickExport ColorspaceType GetPixelCacheColorspace(const Cache cache)
2550 assert(cache != (Cache) NULL);
2551 cache_info=(CacheInfo *) cache;
2552 assert(cache_info->signature == MagickSignature);
2553 if (cache_info->debug != MagickFalse)
2554 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2555 cache_info->filename);
2556 return(cache_info->colorspace);
2560 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2564 + G e t P i x e l C a c h e M e t h o d s %
2568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2570 % GetPixelCacheMethods() initializes the CacheMethods structure.
2572 % The format of the GetPixelCacheMethods() method is:
2574 % void GetPixelCacheMethods(CacheMethods *cache_methods)
2576 % A description of each parameter follows:
2578 % o cache_methods: Specifies a pointer to a CacheMethods structure.
2581 MagickExport void GetPixelCacheMethods(CacheMethods *cache_methods)
2583 assert(cache_methods != (CacheMethods *) NULL);
2584 (void) ResetMagickMemory(cache_methods,0,sizeof(*cache_methods));
2585 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2586 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2587 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2588 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2589 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2590 cache_methods->get_authentic_indexes_from_handler=
2591 GetAuthenticIndexesFromCache;
2592 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2593 cache_methods->get_one_authentic_pixel_from_handler=
2594 GetOneAuthenticPixelFromCache;
2595 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2596 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2597 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2605 + G e t P i x e l C a c h e N e x u s E x t e n t %
2609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2611 % GetPixelCacheNexusExtent() returns the extent of the pixels associated with
2612 % the last call to SetPixelCacheNexusPixels() or GetPixelCacheNexusPixels().
2614 % The format of the GetPixelCacheNexusExtent() method is:
2616 % MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2617 % NexusInfo *nexus_info)
2619 % A description of each parameter follows:
2621 % o nexus_info: the nexus info.
2624 MagickExport MagickSizeType GetPixelCacheNexusExtent(const Cache cache,
2625 NexusInfo *nexus_info)
2633 assert(cache != (const Cache) NULL);
2634 cache_info=(CacheInfo *) cache;
2635 assert(cache_info->signature == MagickSignature);
2636 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2638 return((MagickSizeType) cache_info->columns*cache_info->rows);
2643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2647 + 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 %
2651 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2653 % GetPixelCacheNexusIndexes() returns the indexes associated with the
2654 % specified cache nexus.
2656 % The format of the GetPixelCacheNexusIndexes() method is:
2658 % IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2659 % NexusInfo *nexus_info)
2661 % A description of each parameter follows:
2663 % o cache: the pixel cache.
2665 % o nexus_info: the cache nexus to return the colormap indexes.
2668 MagickExport IndexPacket *GetPixelCacheNexusIndexes(const Cache cache,
2669 NexusInfo *nexus_info)
2674 assert(cache != (const Cache) NULL);
2675 cache_info=(CacheInfo *) cache;
2676 assert(cache_info->signature == MagickSignature);
2677 if (cache_info->storage_class == UndefinedClass)
2678 return((IndexPacket *) NULL);
2679 return(nexus_info->indexes);
2683 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2687 + G e t P i x e l C a c h e N e x u s P i x e l s %
2691 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2693 % GetPixelCacheNexusPixels() returns the pixels associated with the specified
2696 % The format of the GetPixelCacheNexusPixels() method is:
2698 % PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2699 % NexusInfo *nexus_info)
2701 % A description of each parameter follows:
2703 % o cache: the pixel cache.
2705 % o nexus_info: the cache nexus to return the pixels.
2708 MagickExport PixelPacket *GetPixelCacheNexusPixels(const Cache cache,
2709 NexusInfo *nexus_info)
2714 assert(cache != (const Cache) NULL);
2715 cache_info=(CacheInfo *) cache;
2716 assert(cache_info->signature == MagickSignature);
2717 if (cache_info->storage_class == UndefinedClass)
2718 return((PixelPacket *) NULL);
2719 return(nexus_info->pixels);
2723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2727 + G e t P i x e l C a c h e P i x e l s %
2731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2733 % GetPixelCachePixels() returns the pixels associated with the specified image.
2735 % The format of the GetPixelCachePixels() method is:
2737 % void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2738 % ExceptionInfo *exception)
2740 % A description of each parameter follows:
2742 % o image: the image.
2744 % o length: the pixel cache length.
2746 % o exception: return any errors or warnings in this structure.
2749 MagickExport void *GetPixelCachePixels(Image *image,MagickSizeType *length,
2750 ExceptionInfo *exception)
2755 assert(image != (const Image *) NULL);
2756 assert(image->signature == MagickSignature);
2757 assert(image->cache != (Cache) NULL);
2758 assert(length != (MagickSizeType *) NULL);
2759 assert(exception != (ExceptionInfo *) NULL);
2760 assert(exception->signature == MagickSignature);
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) lseek(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)
3977 format[MaxTextExtent],
3978 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 cache.
4202 % o initialize: A value other than zero initializes the persistent pixel
4205 % o offset: the offset in the persistent cache to store pixels.
4207 % o exception: return any errors or warnings in this structure.
4210 MagickExport MagickBooleanType PersistPixelCache(Image *image,
4211 const char *filename,const MagickBooleanType attach,MagickOffsetType *offset,
4212 ExceptionInfo *exception)
4227 assert(image != (Image *) NULL);
4228 assert(image->signature == MagickSignature);
4229 if (image->debug != MagickFalse)
4230 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4231 assert(image->cache != (void *) NULL);
4232 assert(filename != (const char *) NULL);
4233 assert(offset != (MagickOffsetType *) NULL);
4234 page_size=GetMagickPageSize();
4235 cache_info=(CacheInfo *) image->cache;
4236 assert(cache_info->signature == MagickSignature);
4237 if (attach != MagickFalse)
4240 Attach existing persistent pixel cache.
4242 if (image->debug != MagickFalse)
4243 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4244 "attach persistent cache");
4245 (void) CopyMagickString(cache_info->cache_filename,filename,
4247 cache_info->type=DiskCache;
4248 cache_info->offset=(*offset);
4249 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4250 return(MagickFalse);
4251 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4254 if ((cache_info->mode != ReadMode) && (cache_info->type != MemoryCache) &&
4255 (cache_info->reference_count == 1))
4257 LockSemaphoreInfo(cache_info->semaphore);
4258 if ((cache_info->mode != ReadMode) &&
4259 (cache_info->type != MemoryCache) &&
4260 (cache_info->reference_count == 1))
4266 Usurp existing persistent pixel cache.
4268 status=rename(cache_info->cache_filename,filename);
4271 (void) CopyMagickString(cache_info->cache_filename,filename,
4273 *offset+=cache_info->length+page_size-(cache_info->length %
4275 UnlockSemaphoreInfo(cache_info->semaphore);
4276 cache_info=(CacheInfo *) ReferencePixelCache(cache_info);
4277 if (image->debug != MagickFalse)
4278 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4279 "Usurp resident persistent cache");
4283 UnlockSemaphoreInfo(cache_info->semaphore);
4286 Clone persistent pixel cache.
4288 clone_image=(*image);
4289 clone_info=(CacheInfo *) clone_image.cache;
4290 image->cache=ClonePixelCache(cache_info);
4291 cache_info=(CacheInfo *) ReferencePixelCache(image->cache);
4292 (void) CopyMagickString(cache_info->cache_filename,filename,MaxTextExtent);
4293 cache_info->type=DiskCache;
4294 cache_info->offset=(*offset);
4295 cache_info=(CacheInfo *) image->cache;
4296 status=OpenPixelCache(image,IOMode,exception);
4297 if (status != MagickFalse)
4298 status=ClonePixelCachePixels(cache_info,clone_info,&image->exception);
4299 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4300 clone_info=(CacheInfo *) DestroyPixelCache(clone_info);
4305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4309 + Q u e u e A u t h e n t i c N e x u s %
4313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4315 % QueueAuthenticNexus() allocates an region to store image pixels as defined
4316 % by the region rectangle and returns a pointer to the region. This region is
4317 % subsequently transferred from the pixel cache with
4318 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4319 % pixels are transferred, otherwise a NULL is returned.
4321 % The format of the QueueAuthenticNexus() method is:
4323 % PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4324 % const ssize_t y,const size_t columns,const size_t rows,
4325 % NexusInfo *nexus_info,ExceptionInfo *exception)
4327 % A description of each parameter follows:
4329 % o image: the image.
4331 % o x,y,columns,rows: These values define the perimeter of a region of
4334 % o nexus_info: the cache nexus to set.
4336 % o exception: return any errors or warnings in this structure.
4339 MagickExport PixelPacket *QueueAuthenticNexus(Image *image,const ssize_t x,
4340 const ssize_t y,const size_t columns,const size_t rows,NexusInfo *nexus_info,
4341 ExceptionInfo *exception)
4356 Validate pixel cache geometry.
4358 assert(image != (const Image *) NULL);
4359 assert(image->signature == MagickSignature);
4360 assert(image->cache != (Cache) NULL);
4361 cache_info=(CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
4362 assert(cache_info->signature == MagickSignature);
4363 if (cache_info == (Cache) NULL)
4364 return((PixelPacket *) NULL);
4365 if ((cache_info->columns == 0) && (cache_info->rows == 0))
4367 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4368 "NoPixelsDefinedInCache","`%s'",image->filename);
4369 return((PixelPacket *) NULL);
4371 if ((x < 0) || (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4372 (y >= (ssize_t) cache_info->rows))
4374 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4375 "PixelsAreNotAuthentic","`%s'",image->filename);
4376 return((PixelPacket *) NULL);
4378 offset=(MagickOffsetType) y*cache_info->columns+x;
4380 return((PixelPacket *) NULL);
4381 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4382 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4383 if ((MagickSizeType) offset >= number_pixels)
4384 return((PixelPacket *) NULL);
4390 region.width=columns;
4392 return(SetPixelCacheNexusPixels(image,®ion,nexus_info,exception));
4396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4400 + 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 %
4404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4406 % QueueAuthenticPixelsCache() allocates an region to store image pixels as
4407 % defined by the region rectangle and returns a pointer to the region. This
4408 % region is subsequently transferred from the pixel cache with
4409 % SyncAuthenticPixelsCache(). A pointer to the pixels is returned if the
4410 % pixels are transferred, otherwise a NULL is returned.
4412 % The format of the QueueAuthenticPixelsCache() method is:
4414 % PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4415 % const ssize_t y,const size_t columns,const size_t rows,
4416 % ExceptionInfo *exception)
4418 % A description of each parameter follows:
4420 % o image: the image.
4422 % o x,y,columns,rows: These values define the perimeter of a region of
4425 % o exception: return any errors or warnings in this structure.
4428 static PixelPacket *QueueAuthenticPixelsCache(Image *image,const ssize_t x,
4429 const ssize_t y,const size_t columns,const size_t rows,
4430 ExceptionInfo *exception)
4436 id = GetOpenMPThreadId();
4438 assert(image != (const Image *) NULL);
4439 assert(image->signature == MagickSignature);
4440 assert(image->cache != (Cache) NULL);
4441 cache_info=(CacheInfo *) image->cache;
4442 assert(cache_info->signature == MagickSignature);
4443 assert(id < (int) cache_info->number_threads);
4444 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4453 % Q u e u e A u t h e n t i c P i x e l s %
4457 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4459 % QueueAuthenticPixels() queues a mutable pixel region. If the region is
4460 % successfully intialized a pointer to a PixelPacket array representing the
4461 % region is returned, otherwise NULL is returned. The returned pointer may
4462 % point to a temporary working buffer for the pixels or it may point to the
4463 % final location of the pixels in memory.
4465 % Write-only access means that any existing pixel values corresponding to
4466 % the region are ignored. This is useful if the initial image is being
4467 % created from scratch, or if the existing pixel values are to be
4468 % completely replaced without need to refer to their pre-existing values.
4469 % The application is free to read and write the pixel buffer returned by
4470 % QueueAuthenticPixels() any way it pleases. QueueAuthenticPixels() does not
4471 % initialize the pixel array values. Initializing pixel array values is the
4472 % application's responsibility.
4474 % Performance is maximized if the selected region is part of one row, or
4475 % one or more full rows, since then there is opportunity to access the
4476 % pixels in-place (without a copy) if the image is in memory, or in a
4477 % memory-mapped file. The returned pointer must *never* be deallocated
4480 % Pixels accessed via the returned pointer represent a simple array of type
4481 % PixelPacket. If the image type is CMYK or the storage class is PseudoClass,
4482 % call GetAuthenticIndexQueue() after invoking GetAuthenticPixels() to obtain
4483 % the black color component or the colormap indexes (of type IndexPacket)
4484 % corresponding to the region. Once the PixelPacket (and/or IndexPacket)
4485 % array has been updated, the changes must be saved back to the underlying
4486 % image using SyncAuthenticPixels() or they may be lost.
4488 % The format of the QueueAuthenticPixels() method is:
4490 % PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4491 % const ssize_t y,const size_t columns,const size_t rows,
4492 % ExceptionInfo *exception)
4494 % A description of each parameter follows:
4496 % o image: the image.
4498 % o x,y,columns,rows: These values define the perimeter of a region of
4501 % o exception: return any errors or warnings in this structure.
4504 MagickExport PixelPacket *QueueAuthenticPixels(Image *image,const ssize_t x,
4505 const ssize_t y,const size_t columns,const size_t rows,
4506 ExceptionInfo *exception)
4512 id = GetOpenMPThreadId();
4514 assert(image != (Image *) NULL);
4515 assert(image->signature == MagickSignature);
4516 assert(image->cache != (Cache) NULL);
4517 cache_info=(CacheInfo *) image->cache;
4518 assert(cache_info->signature == MagickSignature);
4519 if (cache_info->methods.queue_authentic_pixels_handler !=
4520 (QueueAuthenticPixelsHandler) NULL)
4521 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4523 assert(id < (int) cache_info->number_threads);
4524 return(QueueAuthenticNexus(image,x,y,columns,rows,cache_info->nexus_info[id],
4529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4533 + R e a d P i x e l C a c h e I n d e x e s %
4537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4539 % ReadPixelCacheIndexes() reads colormap indexes from the specified region of
4542 % The format of the ReadPixelCacheIndexes() method is:
4544 % MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4545 % NexusInfo *nexus_info,ExceptionInfo *exception)
4547 % A description of each parameter follows:
4549 % o cache_info: the pixel cache.
4551 % o nexus_info: the cache nexus to read the colormap indexes.
4553 % o exception: return any errors or warnings in this structure.
4556 static MagickBooleanType ReadPixelCacheIndexes(CacheInfo *cache_info,
4557 NexusInfo *nexus_info,ExceptionInfo *exception)
4567 register IndexPacket
4576 if (cache_info->active_index_channel == MagickFalse)
4577 return(MagickFalse);
4578 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4580 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4581 nexus_info->region.x;
4582 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
4583 rows=nexus_info->region.height;
4585 q=nexus_info->indexes;
4586 switch (cache_info->type)
4591 register IndexPacket
4595 Read indexes from memory.
4597 if ((cache_info->columns == nexus_info->region.width) &&
4598 (extent == (MagickSizeType) ((size_t) extent)))
4603 p=cache_info->indexes+offset;
4604 for (y=0; y < (ssize_t) rows; y++)
4606 (void) memcpy(q,p,(size_t) length);
4607 p+=cache_info->columns;
4608 q+=nexus_info->region.width;
4615 Read indexes from disk.
4617 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4619 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4620 cache_info->cache_filename);
4621 return(MagickFalse);
4623 if ((cache_info->columns == nexus_info->region.width) &&
4624 (extent <= MagickMaxBufferExtent))
4629 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4630 for (y=0; y < (ssize_t) rows; y++)
4632 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4633 sizeof(PixelPacket)+offset*sizeof(*q),length,(unsigned char *) q);
4634 if ((MagickSizeType) count < length)
4636 offset+=cache_info->columns;
4637 q+=nexus_info->region.width;
4639 if (y < (ssize_t) rows)
4641 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4642 cache_info->cache_filename);
4643 return(MagickFalse);
4650 if ((cache_info->debug != MagickFalse) &&
4651 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4652 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4653 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4654 nexus_info->region.width,(double) nexus_info->region.height,(double)
4655 nexus_info->region.x,(double) nexus_info->region.y);
4660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4664 + R e a d P i x e l C a c h e P i x e l s %
4668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4670 % ReadPixelCachePixels() reads pixels from the specified region of the pixel
4673 % The format of the ReadPixelCachePixels() method is:
4675 % MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4676 % NexusInfo *nexus_info,ExceptionInfo *exception)
4678 % A description of each parameter follows:
4680 % o cache_info: the pixel cache.
4682 % o nexus_info: the cache nexus to read the pixels.
4684 % o exception: return any errors or warnings in this structure.
4687 static MagickBooleanType ReadPixelCachePixels(CacheInfo *cache_info,
4688 NexusInfo *nexus_info,ExceptionInfo *exception)
4698 register PixelPacket
4707 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
4709 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4710 nexus_info->region.x;
4711 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
4712 rows=nexus_info->region.height;
4714 q=nexus_info->pixels;
4715 switch (cache_info->type)
4720 register PixelPacket
4724 Read pixels from memory.
4726 if ((cache_info->columns == nexus_info->region.width) &&
4727 (extent == (MagickSizeType) ((size_t) extent)))
4732 p=cache_info->pixels+offset;
4733 for (y=0; y < (ssize_t) rows; y++)
4735 (void) memcpy(q,p,(size_t) length);
4736 p+=cache_info->columns;
4737 q+=nexus_info->region.width;
4744 Read pixels from disk.
4746 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4748 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
4749 cache_info->cache_filename);
4750 return(MagickFalse);
4752 if ((cache_info->columns == nexus_info->region.width) &&
4753 (extent <= MagickMaxBufferExtent))
4758 for (y=0; y < (ssize_t) rows; y++)
4760 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4761 sizeof(*q),length,(unsigned char *) q);
4762 if ((MagickSizeType) count < length)
4764 offset+=cache_info->columns;
4765 q+=nexus_info->region.width;
4767 if (y < (ssize_t) rows)
4769 ThrowFileException(exception,CacheError,"UnableToReadPixelCache",
4770 cache_info->cache_filename);
4771 return(MagickFalse);
4778 if ((cache_info->debug != MagickFalse) &&
4779 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4780 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4781 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4782 nexus_info->region.width,(double) nexus_info->region.height,(double)
4783 nexus_info->region.x,(double) nexus_info->region.y);
4788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4792 + R e f e r e n c e P i x e l C a c h e %
4796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4798 % ReferencePixelCache() increments the reference count associated with the
4799 % pixel cache returning a pointer to the cache.
4801 % The format of the ReferencePixelCache method is:
4803 % Cache ReferencePixelCache(Cache cache_info)
4805 % A description of each parameter follows:
4807 % o cache_info: the pixel cache.
4810 MagickExport Cache ReferencePixelCache(Cache cache)
4815 assert(cache != (Cache *) NULL);
4816 cache_info=(CacheInfo *) cache;
4817 assert(cache_info->signature == MagickSignature);
4818 LockSemaphoreInfo(cache_info->semaphore);
4819 cache_info->reference_count++;
4820 UnlockSemaphoreInfo(cache_info->semaphore);
4825 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4829 + S e t P i x e l C a c h e M e t h o d s %
4833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4835 % SetPixelCacheMethods() sets the image pixel methods to the specified ones.
4837 % The format of the SetPixelCacheMethods() method is:
4839 % SetPixelCacheMethods(Cache *,CacheMethods *cache_methods)
4841 % A description of each parameter follows:
4843 % o cache: the pixel cache.
4845 % o cache_methods: Specifies a pointer to a CacheMethods structure.
4848 MagickExport void SetPixelCacheMethods(Cache cache,CacheMethods *cache_methods)
4853 GetOneAuthenticPixelFromHandler
4854 get_one_authentic_pixel_from_handler;
4856 GetOneVirtualPixelFromHandler
4857 get_one_virtual_pixel_from_handler;
4860 Set cache pixel methods.
4862 assert(cache != (Cache) NULL);
4863 assert(cache_methods != (CacheMethods *) NULL);
4864 cache_info=(CacheInfo *) cache;
4865 assert(cache_info->signature == MagickSignature);
4866 if (cache_info->debug != MagickFalse)
4867 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4868 cache_info->filename);
4869 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
4870 cache_info->methods.get_virtual_pixel_handler=
4871 cache_methods->get_virtual_pixel_handler;
4872 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
4873 cache_info->methods.destroy_pixel_handler=
4874 cache_methods->destroy_pixel_handler;
4875 if (cache_methods->get_virtual_indexes_from_handler !=
4876 (GetVirtualIndexesFromHandler) NULL)
4877 cache_info->methods.get_virtual_indexes_from_handler=
4878 cache_methods->get_virtual_indexes_from_handler;
4879 if (cache_methods->get_authentic_pixels_handler !=
4880 (GetAuthenticPixelsHandler) NULL)
4881 cache_info->methods.get_authentic_pixels_handler=
4882 cache_methods->get_authentic_pixels_handler;
4883 if (cache_methods->queue_authentic_pixels_handler !=
4884 (QueueAuthenticPixelsHandler) NULL)
4885 cache_info->methods.queue_authentic_pixels_handler=
4886 cache_methods->queue_authentic_pixels_handler;
4887 if (cache_methods->sync_authentic_pixels_handler !=
4888 (SyncAuthenticPixelsHandler) NULL)
4889 cache_info->methods.sync_authentic_pixels_handler=
4890 cache_methods->sync_authentic_pixels_handler;
4891 if (cache_methods->get_authentic_pixels_from_handler !=
4892 (GetAuthenticPixelsFromHandler) NULL)
4893 cache_info->methods.get_authentic_pixels_from_handler=
4894 cache_methods->get_authentic_pixels_from_handler;
4895 if (cache_methods->get_authentic_indexes_from_handler !=
4896 (GetAuthenticIndexesFromHandler) NULL)
4897 cache_info->methods.get_authentic_indexes_from_handler=
4898 cache_methods->get_authentic_indexes_from_handler;
4899 get_one_virtual_pixel_from_handler=
4900 cache_info->methods.get_one_virtual_pixel_from_handler;
4901 if (get_one_virtual_pixel_from_handler !=
4902 (GetOneVirtualPixelFromHandler) NULL)
4903 cache_info->methods.get_one_virtual_pixel_from_handler=
4904 cache_methods->get_one_virtual_pixel_from_handler;
4905 get_one_authentic_pixel_from_handler=
4906 cache_methods->get_one_authentic_pixel_from_handler;
4907 if (get_one_authentic_pixel_from_handler !=
4908 (GetOneAuthenticPixelFromHandler) NULL)
4909 cache_info->methods.get_one_authentic_pixel_from_handler=
4910 cache_methods->get_one_authentic_pixel_from_handler;
4914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4918 + S e t P i x e l C a c h e N e x u s P i x e l s %
4922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4924 % SetPixelCacheNexusPixels() defines the region of the cache for the
4925 % specified cache nexus.
4927 % The format of the SetPixelCacheNexusPixels() method is:
4929 % PixelPacket SetPixelCacheNexusPixels(const Image *image,
4930 % const RectangleInfo *region,NexusInfo *nexus_info,
4931 % ExceptionInfo *exception)
4933 % A description of each parameter follows:
4935 % o image: the image.
4937 % o region: A pointer to the RectangleInfo structure that defines the
4938 % region of this particular cache nexus.
4940 % o nexus_info: the cache nexus to set.
4942 % o exception: return any errors or warnings in this structure.
4946 static inline MagickBooleanType AcquireCacheNexusPixels(CacheInfo *cache_info,
4947 NexusInfo *nexus_info,ExceptionInfo *exception)
4949 if (nexus_info->length != (MagickSizeType) ((size_t) nexus_info->length))
4950 return(MagickFalse);
4951 nexus_info->mapped=MagickFalse;
4952 nexus_info->cache=(PixelPacket *) AcquireMagickMemory((size_t)
4953 nexus_info->length);
4954 if (nexus_info->cache == (PixelPacket *) NULL)
4956 nexus_info->mapped=MagickTrue;
4957 nexus_info->cache=(PixelPacket *) MapBlob(-1,IOMode,0,(size_t)
4958 nexus_info->length);
4960 if (nexus_info->cache == (PixelPacket *) NULL)
4962 (void) ThrowMagickException(exception,GetMagickModule(),
4963 ResourceLimitError,"MemoryAllocationFailed","`%s'",
4964 cache_info->filename);
4965 return(MagickFalse);
4970 static PixelPacket *SetPixelCacheNexusPixels(const Image *image,
4971 const RectangleInfo *region,NexusInfo *nexus_info,ExceptionInfo *exception)
4983 cache_info=(CacheInfo *) image->cache;
4984 assert(cache_info->signature == MagickSignature);
4985 if (cache_info->type == UndefinedCache)
4986 return((PixelPacket *) NULL);
4987 nexus_info->region=(*region);
4988 if ((cache_info->type != DiskCache) && (cache_info->type != PingCache) &&
4989 (image->clip_mask == (Image *) NULL) && (image->mask == (Image *) NULL))
4995 x=nexus_info->region.x+(ssize_t) nexus_info->region.width-1;
4996 y=nexus_info->region.y+(ssize_t) nexus_info->region.height-1;
4997 if (((nexus_info->region.x >= 0) && (x < (ssize_t) cache_info->columns) &&
4998 (nexus_info->region.y >= 0) && (y < (ssize_t) cache_info->rows)) &&
4999 ((nexus_info->region.height == 1UL) || ((nexus_info->region.x == 0) &&
5000 ((nexus_info->region.width == cache_info->columns) ||
5001 ((nexus_info->region.width % cache_info->columns) == 0)))))
5007 Pixels are accessed directly from memory.
5009 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5010 nexus_info->region.x;
5011 nexus_info->pixels=cache_info->pixels+offset;
5012 nexus_info->indexes=(IndexPacket *) NULL;
5013 if (cache_info->active_index_channel != MagickFalse)
5014 nexus_info->indexes=cache_info->indexes+offset;
5015 return(nexus_info->pixels);
5019 Pixels are stored in a cache region until they are synced to the cache.
5021 number_pixels=(MagickSizeType) nexus_info->region.width*
5022 nexus_info->region.height;
5023 length=number_pixels*sizeof(PixelPacket);
5024 if (cache_info->active_index_channel != MagickFalse)
5025 length+=number_pixels*sizeof(IndexPacket);
5026 if (nexus_info->cache == (PixelPacket *) NULL)
5028 nexus_info->length=length;
5029 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5030 if (status == MagickFalse)
5032 nexus_info->length=0;
5033 return((PixelPacket *) NULL);
5037 if (nexus_info->length != length)
5039 RelinquishCacheNexusPixels(nexus_info);
5040 nexus_info->length=length;
5041 status=AcquireCacheNexusPixels(cache_info,nexus_info,exception);
5042 if (status == MagickFalse)
5044 nexus_info->length=0;
5045 return((PixelPacket *) NULL);
5048 nexus_info->pixels=nexus_info->cache;
5049 nexus_info->indexes=(IndexPacket *) NULL;
5050 if (cache_info->active_index_channel != MagickFalse)
5051 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5052 return(nexus_info->pixels);
5056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5060 % 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 %
5064 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5066 % SetPixelCacheVirtualMethod() sets the "virtual pixels" method for the
5067 % pixel cache and returns the previous setting. A virtual pixel is any pixel
5068 % access that is outside the boundaries of the image cache.
5070 % The format of the SetPixelCacheVirtualMethod() method is:
5072 % VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5073 % const VirtualPixelMethod virtual_pixel_method)
5075 % A description of each parameter follows:
5077 % o image: the image.
5079 % o virtual_pixel_method: choose the type of virtual pixel.
5082 MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(const Image *image,
5083 const VirtualPixelMethod virtual_pixel_method)
5091 assert(image != (Image *) NULL);
5092 assert(image->signature == MagickSignature);
5093 if (image->debug != MagickFalse)
5094 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5095 assert(image->cache != (Cache) NULL);
5096 cache_info=(CacheInfo *) image->cache;
5097 assert(cache_info->signature == MagickSignature);
5098 method=cache_info->virtual_pixel_method;
5099 cache_info->virtual_pixel_method=virtual_pixel_method;
5104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5108 + 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 %
5112 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5114 % SyncAuthenticPixelCacheNexus() saves the authentic image pixels to the
5115 % in-memory or disk cache. The method returns MagickTrue if the pixel region
5116 % is synced, otherwise MagickFalse.
5118 % The format of the SyncAuthenticPixelCacheNexus() method is:
5120 % MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5121 % NexusInfo *nexus_info,ExceptionInfo *exception)
5123 % A description of each parameter follows:
5125 % o image: the image.
5127 % o nexus_info: the cache nexus to sync.
5129 % o exception: return any errors or warnings in this structure.
5132 MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(Image *image,
5133 NexusInfo *nexus_info,ExceptionInfo *exception)
5142 Transfer pixels to the cache.
5144 assert(image != (Image *) NULL);
5145 assert(image->signature == MagickSignature);
5146 if (image->cache == (Cache) NULL)
5147 ThrowBinaryException(CacheError,"PixelCacheIsNotOpen",image->filename);
5148 cache_info=(CacheInfo *) image->cache;
5149 assert(cache_info->signature == MagickSignature);
5150 if (cache_info->type == UndefinedCache)
5151 return(MagickFalse);
5152 if ((image->clip_mask != (Image *) NULL) &&
5153 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5154 return(MagickFalse);
5155 if ((image->mask != (Image *) NULL) &&
5156 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5157 return(MagickFalse);
5158 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5160 assert(cache_info->signature == MagickSignature);
5161 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5162 if ((cache_info->active_index_channel != MagickFalse) &&
5163 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5164 return(MagickFalse);
5169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5173 + S y n c A u t h e n t i c P i x e l C a c h e %
5177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5179 % SyncAuthenticPixelsCache() saves the authentic image pixels to the in-memory
5180 % or disk cache. The method returns MagickTrue if the pixel region is synced,
5181 % otherwise MagickFalse.
5183 % The format of the SyncAuthenticPixelsCache() method is:
5185 % MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5186 % ExceptionInfo *exception)
5188 % A description of each parameter follows:
5190 % o image: the image.
5192 % o exception: return any errors or warnings in this structure.
5195 static MagickBooleanType SyncAuthenticPixelsCache(Image *image,
5196 ExceptionInfo *exception)
5202 id = GetOpenMPThreadId();
5204 assert(image != (Image *) NULL);
5205 assert(image->signature == MagickSignature);
5206 assert(image->cache != (Cache) NULL);
5207 cache_info=(CacheInfo *) image->cache;
5208 assert(cache_info->signature == MagickSignature);
5209 assert(id < (int) cache_info->number_threads);
5210 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5219 % S y n c A u t h e n t i c P i x e l s %
5223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5225 % SyncAuthenticPixels() saves the image pixels to the in-memory or disk cache.
5226 % The method returns MagickTrue if the pixel region is flushed, otherwise
5229 % The format of the SyncAuthenticPixels() method is:
5231 % MagickBooleanType SyncAuthenticPixels(Image *image,
5232 % ExceptionInfo *exception)
5234 % A description of each parameter follows:
5236 % o image: the image.
5238 % o exception: return any errors or warnings in this structure.
5241 MagickExport MagickBooleanType SyncAuthenticPixels(Image *image,
5242 ExceptionInfo *exception)
5248 id = GetOpenMPThreadId();
5250 assert(image != (Image *) NULL);
5251 assert(image->signature == MagickSignature);
5252 assert(image->cache != (Cache) NULL);
5253 cache_info=(CacheInfo *) image->cache;
5254 assert(cache_info->signature == MagickSignature);
5255 if (cache_info->methods.sync_authentic_pixels_handler !=
5256 (SyncAuthenticPixelsHandler) NULL)
5257 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5258 assert(id < (int) cache_info->number_threads);
5259 return(SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[id],
5264 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5268 + W r i t e P i x e l C a c h e I n d e x e s %
5272 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5274 % WritePixelCacheIndexes() writes the colormap indexes to the specified
5275 % region of the pixel cache.
5277 % The format of the WritePixelCacheIndexes() method is:
5279 % MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5280 % NexusInfo *nexus_info,ExceptionInfo *exception)
5282 % A description of each parameter follows:
5284 % o cache_info: the pixel cache.
5286 % o nexus_info: the cache nexus to write the colormap indexes.
5288 % o exception: return any errors or warnings in this structure.
5291 static MagickBooleanType WritePixelCacheIndexes(CacheInfo *cache_info,
5292 NexusInfo *nexus_info,ExceptionInfo *exception)
5302 register const IndexPacket
5311 if (cache_info->active_index_channel == MagickFalse)
5312 return(MagickFalse);
5313 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5315 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5316 nexus_info->region.x;
5317 length=(MagickSizeType) nexus_info->region.width*sizeof(IndexPacket);
5318 rows=nexus_info->region.height;
5319 extent=(MagickSizeType) length*rows;
5320 p=nexus_info->indexes;
5321 switch (cache_info->type)
5326 register IndexPacket
5330 Write indexes to memory.
5332 if ((cache_info->columns == nexus_info->region.width) &&
5333 (extent == (MagickSizeType) ((size_t) extent)))
5338 q=cache_info->indexes+offset;
5339 for (y=0; y < (ssize_t) rows; y++)
5341 (void) memcpy(q,p,(size_t) length);
5342 p+=nexus_info->region.width;
5343 q+=cache_info->columns;
5350 Write indexes to disk.
5352 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5354 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5355 cache_info->cache_filename);
5356 return(MagickFalse);
5358 if ((cache_info->columns == nexus_info->region.width) &&
5359 (extent <= MagickMaxBufferExtent))
5364 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5365 for (y=0; y < (ssize_t) rows; y++)
5367 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5368 sizeof(PixelPacket)+offset*sizeof(*p),length,(const unsigned char *)
5370 if ((MagickSizeType) count < length)
5372 p+=nexus_info->region.width;
5373 offset+=cache_info->columns;
5375 if (y < (ssize_t) rows)
5377 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5378 cache_info->cache_filename);
5379 return(MagickFalse);
5386 if ((cache_info->debug != MagickFalse) &&
5387 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5388 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5389 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5390 nexus_info->region.width,(double) nexus_info->region.height,(double)
5391 nexus_info->region.x,(double) nexus_info->region.y);
5396 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5400 + W r i t e C a c h e P i x e l s %
5404 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5406 % WritePixelCachePixels() writes image pixels to the specified region of the
5409 % The format of the WritePixelCachePixels() method is:
5411 % MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5412 % NexusInfo *nexus_info,ExceptionInfo *exception)
5414 % A description of each parameter follows:
5416 % o cache_info: the pixel cache.
5418 % o nexus_info: the cache nexus to write the pixels.
5420 % o exception: return any errors or warnings in this structure.
5423 static MagickBooleanType WritePixelCachePixels(CacheInfo *cache_info,
5424 NexusInfo *nexus_info,ExceptionInfo *exception)
5434 register const PixelPacket
5443 if (IsNexusInCore(cache_info,nexus_info) != MagickFalse)
5445 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5446 nexus_info->region.x;
5447 length=(MagickSizeType) nexus_info->region.width*sizeof(PixelPacket);
5448 rows=nexus_info->region.height;
5450 p=nexus_info->pixels;
5451 switch (cache_info->type)
5456 register PixelPacket
5460 Write pixels to memory.
5462 if ((cache_info->columns == nexus_info->region.width) &&
5463 (extent == (MagickSizeType) ((size_t) extent)))
5468 q=cache_info->pixels+offset;
5469 for (y=0; y < (ssize_t) rows; y++)
5471 (void) memcpy(q,p,(size_t) length);
5472 p+=nexus_info->region.width;
5473 q+=cache_info->columns;
5480 Write pixels to disk.
5482 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5484 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
5485 cache_info->cache_filename);
5486 return(MagickFalse);
5488 if ((cache_info->columns == nexus_info->region.width) &&
5489 (extent <= MagickMaxBufferExtent))
5494 for (y=0; y < (ssize_t) rows; y++)
5496 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5497 sizeof(*p),length,(const unsigned char *) p);
5498 if ((MagickSizeType) count < length)
5500 p+=nexus_info->region.width;
5501 offset+=cache_info->columns;
5503 if (y < (ssize_t) rows)
5505 ThrowFileException(exception,CacheError,"UnableToWritePixelCache",
5506 cache_info->cache_filename);
5507 return(MagickFalse);
5514 if ((cache_info->debug != MagickFalse) &&
5515 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5516 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5517 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5518 nexus_info->region.width,(double) nexus_info->region.height,(double)
5519 nexus_info->region.x,(double) nexus_info->region.y);